├── .gitignore
├── screenshot.png
├── anybar_patreon.png
├── AnyBar
├── Resources
│ ├── red@2x.png
│ ├── black@2x.png
│ ├── blue@2x.png
│ ├── cyan@2x.png
│ ├── green@2x.png
│ ├── white@2x.png
│ ├── filled@2x.png
│ ├── hollow@2x.png
│ ├── orange@2x.png
│ ├── purple@2x.png
│ ├── question@2x.png
│ ├── yellow@2x.png
│ └── exclamation@2x.png
├── Images.xcassets
│ └── AppIcon.appiconset
│ │ ├── icon_128x128.png
│ │ ├── icon_512x512.png
│ │ ├── icon_128x128@2x.png
│ │ ├── icon_512x512@2x.png
│ │ └── Contents.json
├── main.m
├── AppDelegate.h
├── AnyBarApp.m
├── AnyBarApp.h
├── Base.lproj
│ └── MainMenu.xib
├── Info.plist
├── AnyBar.sdef
├── AppDelegate.m
├── GCDAsyncUdpSocket.h
└── GCDAsyncSocket.h
├── Tests
├── test-osa-script.applescript
├── control-anybar.applescript
├── osa-test.sh
└── Makefile
├── AnyBar.xcodeproj
├── project.xcworkspace
│ ├── contents.xcworkspacedata
│ ├── xcuserdata
│ │ └── prokopov.xcuserdatad
│ │ │ ├── UserInterfaceState.xcuserstate
│ │ │ └── WorkspaceSettings.xcsettings
│ └── xcshareddata
│ │ ├── IDEWorkspaceChecks.plist
│ │ └── AnyBar.xccheckout
├── xcuserdata
│ └── prokopov.xcuserdatad
│ │ └── xcschemes
│ │ ├── xcschememanagement.plist
│ │ └── AnyBar.xcscheme
└── project.pbxproj
├── CHANGELOG.md
├── README.md
└── LICENSE
/.gitignore:
--------------------------------------------------------------------------------
1 | xcuserdata/
2 | build
3 | *.zip
--------------------------------------------------------------------------------
/screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tonsky/AnyBar/HEAD/screenshot.png
--------------------------------------------------------------------------------
/anybar_patreon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tonsky/AnyBar/HEAD/anybar_patreon.png
--------------------------------------------------------------------------------
/AnyBar/Resources/red@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tonsky/AnyBar/HEAD/AnyBar/Resources/red@2x.png
--------------------------------------------------------------------------------
/AnyBar/Resources/black@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tonsky/AnyBar/HEAD/AnyBar/Resources/black@2x.png
--------------------------------------------------------------------------------
/AnyBar/Resources/blue@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tonsky/AnyBar/HEAD/AnyBar/Resources/blue@2x.png
--------------------------------------------------------------------------------
/AnyBar/Resources/cyan@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tonsky/AnyBar/HEAD/AnyBar/Resources/cyan@2x.png
--------------------------------------------------------------------------------
/AnyBar/Resources/green@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tonsky/AnyBar/HEAD/AnyBar/Resources/green@2x.png
--------------------------------------------------------------------------------
/AnyBar/Resources/white@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tonsky/AnyBar/HEAD/AnyBar/Resources/white@2x.png
--------------------------------------------------------------------------------
/AnyBar/Resources/filled@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tonsky/AnyBar/HEAD/AnyBar/Resources/filled@2x.png
--------------------------------------------------------------------------------
/AnyBar/Resources/hollow@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tonsky/AnyBar/HEAD/AnyBar/Resources/hollow@2x.png
--------------------------------------------------------------------------------
/AnyBar/Resources/orange@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tonsky/AnyBar/HEAD/AnyBar/Resources/orange@2x.png
--------------------------------------------------------------------------------
/AnyBar/Resources/purple@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tonsky/AnyBar/HEAD/AnyBar/Resources/purple@2x.png
--------------------------------------------------------------------------------
/AnyBar/Resources/question@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tonsky/AnyBar/HEAD/AnyBar/Resources/question@2x.png
--------------------------------------------------------------------------------
/AnyBar/Resources/yellow@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tonsky/AnyBar/HEAD/AnyBar/Resources/yellow@2x.png
--------------------------------------------------------------------------------
/Tests/test-osa-script.applescript:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tonsky/AnyBar/HEAD/Tests/test-osa-script.applescript
--------------------------------------------------------------------------------
/AnyBar/Resources/exclamation@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tonsky/AnyBar/HEAD/AnyBar/Resources/exclamation@2x.png
--------------------------------------------------------------------------------
/AnyBar/Images.xcassets/AppIcon.appiconset/icon_128x128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tonsky/AnyBar/HEAD/AnyBar/Images.xcassets/AppIcon.appiconset/icon_128x128.png
--------------------------------------------------------------------------------
/AnyBar/Images.xcassets/AppIcon.appiconset/icon_512x512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tonsky/AnyBar/HEAD/AnyBar/Images.xcassets/AppIcon.appiconset/icon_512x512.png
--------------------------------------------------------------------------------
/AnyBar/Images.xcassets/AppIcon.appiconset/icon_128x128@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tonsky/AnyBar/HEAD/AnyBar/Images.xcassets/AppIcon.appiconset/icon_128x128@2x.png
--------------------------------------------------------------------------------
/AnyBar/Images.xcassets/AppIcon.appiconset/icon_512x512@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tonsky/AnyBar/HEAD/AnyBar/Images.xcassets/AppIcon.appiconset/icon_512x512@2x.png
--------------------------------------------------------------------------------
/Tests/control-anybar.applescript:
--------------------------------------------------------------------------------
1 | tell application "AnyBar" to set image name to "blue"
2 | tell application "AnyBar" to set current to get image name as Unicode text
3 | display notification current
--------------------------------------------------------------------------------
/AnyBar.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/AnyBar.xcodeproj/project.xcworkspace/xcuserdata/prokopov.xcuserdatad/UserInterfaceState.xcuserstate:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tonsky/AnyBar/HEAD/AnyBar.xcodeproj/project.xcworkspace/xcuserdata/prokopov.xcuserdatad/UserInterfaceState.xcuserstate
--------------------------------------------------------------------------------
/AnyBar/main.m:
--------------------------------------------------------------------------------
1 | //
2 | // main.m
3 | // AnyBar
4 | //
5 | // Created by Nikita Prokopov on 14/02/15.
6 | // Copyright (c) 2015 Nikita Prokopov. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | int main(int argc, const char * argv[]) {
12 | return NSApplicationMain(argc, argv);
13 | }
14 |
--------------------------------------------------------------------------------
/AnyBar.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Tests/osa-test.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env osascript
2 |
3 | tell application "AnyBar.app"
4 | launch
5 | activate
6 | end tell
7 |
8 | delay 3
9 |
10 | tell application "AnyBar.app"
11 | set image name to "green"
12 | display notification image name as Unicode text
13 | end tell
14 |
15 | delay 3
16 |
17 | tell application "AnyBar.app"
18 | quit
19 | end tell
20 |
21 |
--------------------------------------------------------------------------------
/AnyBar/AppDelegate.h:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.h
3 | // AnyBar
4 | //
5 | // Created by Nikita Prokopov on 14/02/15.
6 | // Copyright (c) 2015 Nikita Prokopov. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "GCDAsyncUdpSocket.h"
11 |
12 | @interface AppDelegate : NSObject
13 |
14 | //
15 | // OSA Scripting bridge
16 | // @see AnyBarApp.h
17 | //
18 | -(id) osaImageBridge;
19 | -(void) setOsaImageBridge:(id)imgName;
20 |
21 | @end
22 |
23 |
--------------------------------------------------------------------------------
/AnyBar/AnyBarApp.m:
--------------------------------------------------------------------------------
1 | //
2 | // AnyBarApp.h
3 | // AnyBar
4 | //
5 | // Created by Nikita Prokopov on 04/03/15.
6 | // Copyright (c) 2015 Nikita Prokopov. All rights reserved.
7 | //
8 |
9 | #import "AnyBarApp.h"
10 |
11 | @implementation AnyBarApp
12 |
13 | -(id) osaImage {
14 | AppDelegate *delegate = (AppDelegate*)self.delegate;
15 | return [delegate osaImageBridge];
16 | }
17 |
18 | -(void) setOsaImage:(id)imgName {
19 | AppDelegate *delegate = (AppDelegate*)self.delegate;
20 | [delegate setOsaImageBridge:imgName];
21 | }
22 |
23 | @end
24 |
--------------------------------------------------------------------------------
/AnyBar/AnyBarApp.h:
--------------------------------------------------------------------------------
1 | //
2 | // AnyBarApp.h
3 | // AnyBar
4 | //
5 | // Created by Nikita Prokopov on 04/03/15.
6 | // Copyright (c) 2015 Nikita Prokopov. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "AppDelegate.h"
11 |
12 | @interface AnyBarApp : NSApplication
13 |
14 | //
15 | // OSA Scripting endpoints
16 | // @see https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/ScriptableCocoaApplications/SApps_intro/SAppsIntro.html
17 | // @see https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/ScriptableCocoaApplications/SApps_about_apps/SAppsAboutApps.html
18 | //
19 | -(id) osaImage;
20 | -(void) setOsaImage:(id)imgName;
21 |
22 | @end
23 |
--------------------------------------------------------------------------------
/AnyBar.xcodeproj/xcuserdata/prokopov.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | AnyBar.xcscheme
8 |
9 | orderHint
10 | 0
11 |
12 |
13 | SuppressBuildableAutocreation
14 |
15 | C5AB32B71A8F9091002258B6
16 |
17 | primary
18 |
19 |
20 | C5AB32CA1A8F9091002258B6
21 |
22 | primary
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/AnyBar.xcodeproj/project.xcworkspace/xcuserdata/prokopov.xcuserdatad/WorkspaceSettings.xcsettings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | BuildLocationStyle
6 | UseAppPreferences
7 | CustomBuildLocationType
8 | RelativeToDerivedData
9 | DerivedDataLocationStyle
10 | Default
11 | IssueFilterStyle
12 | ShowActiveSchemeOnly
13 | LiveSourceIssuesEnabled
14 |
15 | SnapshotAutomaticallyBeforeSignificantChanges
16 |
17 | SnapshotLocationStyle
18 | Default
19 |
20 |
21 |
--------------------------------------------------------------------------------
/AnyBar/Base.lproj/MainMenu.xib:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | ### 0.2.3 / Feb 18, 2021
2 |
3 | - Added `filled` and `hollow`, removed alternative versions of `black` and `white` #84
4 |
5 | ### 0.2.2 / Nov 3, 2020
6 |
7 | - Specify starting color via `ANYBAR_INIT` #80 #81 thx @Gira-X
8 |
9 | ### 0.2.1 / Aug 28, 2020
10 |
11 | - Correct version metadata
12 |
13 | ### 0.2.0 / Aug 26, 2020
14 |
15 | - Specify app tooltip via `ANYBAR_TITLE` #59 #64 thx @mynameismiek @andrewsjg
16 |
17 | ### 0.1.4
18 |
19 | - Bigger dots
20 | - Render “black” on dark menubar as empty circle and “white” on dark as filled circle (#55)
21 | - Compiled for OS X 10.11
22 |
23 | ### 0.1.3
24 |
25 | - AppleScript support (PR #8, thx [Oleg Kertanov](https://github.com/okertanov))
26 |
27 | ### 0.1.2
28 |
29 | - Dark mode support. In dark mode AnyBar will first check for `_alt@2x.png` or `_alt.png` image first, then falls back to `.png`
30 | - Support for Mavericks actually works
31 |
32 | ### 0.1.1
33 |
34 | - Support for Mavericks (PR #2, thx [Oleg Kertanov](https://github.com/okertanov))
35 | - Support for custom images via ~/.AnyBar (PR #1, thx [Paul Boschmann](https://github.com/pboschmann))
36 |
--------------------------------------------------------------------------------
/AnyBar/Images.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "mac",
5 | "size" : "16x16",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "mac",
10 | "size" : "16x16",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "mac",
15 | "size" : "32x32",
16 | "scale" : "1x"
17 | },
18 | {
19 | "idiom" : "mac",
20 | "size" : "32x32",
21 | "scale" : "2x"
22 | },
23 | {
24 | "size" : "128x128",
25 | "idiom" : "mac",
26 | "filename" : "icon_128x128.png",
27 | "scale" : "1x"
28 | },
29 | {
30 | "size" : "128x128",
31 | "idiom" : "mac",
32 | "filename" : "icon_128x128@2x.png",
33 | "scale" : "2x"
34 | },
35 | {
36 | "idiom" : "mac",
37 | "size" : "256x256",
38 | "scale" : "1x"
39 | },
40 | {
41 | "idiom" : "mac",
42 | "size" : "256x256",
43 | "scale" : "2x"
44 | },
45 | {
46 | "size" : "512x512",
47 | "idiom" : "mac",
48 | "filename" : "icon_512x512.png",
49 | "scale" : "1x"
50 | },
51 | {
52 | "size" : "512x512",
53 | "idiom" : "mac",
54 | "filename" : "icon_512x512@2x.png",
55 | "scale" : "2x"
56 | }
57 | ],
58 | "info" : {
59 | "version" : 1,
60 | "author" : "xcode"
61 | }
62 | }
--------------------------------------------------------------------------------
/AnyBar/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIconFile
10 |
11 | CFBundleIdentifier
12 | $(PRODUCT_BUNDLE_IDENTIFIER)
13 | CFBundleInfoDictionaryVersion
14 | 6.0
15 | CFBundleName
16 | $(PRODUCT_NAME)
17 | CFBundlePackageType
18 | APPL
19 | CFBundleShortVersionString
20 | $(MARKETING_VERSION)
21 | CFBundleSignature
22 | ????
23 | CFBundleVersion
24 | $(CURRENT_PROJECT_VERSION)
25 | LSMinimumSystemVersion
26 | $(MACOSX_DEPLOYMENT_TARGET)
27 | LSUIElement
28 |
29 | NSAppleScriptEnabled
30 | YES
31 | NSHumanReadableCopyright
32 | Copyright © 2020 Nikita Prokopov. All rights reserved.
33 | NSMainNibFile
34 | MainMenu
35 | NSPrincipalClass
36 | AnyBarApp
37 | OSAScriptingDefinition
38 | AnyBar
39 |
40 |
41 |
--------------------------------------------------------------------------------
/Tests/Makefile:
--------------------------------------------------------------------------------
1 | SHELL:=bash
2 | SLEEPT:=3s
3 | PORTS:=1738 1739 1740
4 |
5 | all: tests
6 |
7 | tests: anybar
8 | @echo "Starting..." && \
9 | echo -n " WHITE " && \
10 | for port in $(PORTS) ; do ANYBAR_PORT=$$port open -n ../build/Debug/AnyBar.app ; done && \
11 | sleep $(SLEEPT) && \
12 | echo -n " ORANGE " && \
13 | for port in $(PORTS) ; do echo -n "orange" | nc -4u -w0 localhost $$port ; done && \
14 | sleep $(SLEEPT) && \
15 | echo -n " RGB " && \
16 | echo -n "red" | nc -4u -w0 localhost 1738 && \
17 | echo -n "green" | nc -4u -w0 localhost 1739 && \
18 | echo -n "blue" | nc -4u -w0 localhost 1740 && \
19 | sleep $(SLEEPT) && \
20 | echo -n " BLACK " && \
21 | for port in $(PORTS) ; do echo -n "black" | nc -4u -w0 localhost $$port ; done && \
22 | sleep $(SLEEPT) && \
23 | echo -n " WHITE " && \
24 | for port in $(PORTS) ; do echo -n "white" | nc -4u -w0 localhost $$port ; done && \
25 | sleep $(SLEEPT) && \
26 | echo && \
27 | echo "Stopping..." && \
28 | for port in $(PORTS) ; do echo -n "quit" | nc -4u -w0 localhost $$port ; done && \
29 | sleep $(SLEEPT) && \
30 | echo "Done."
31 |
32 | anybar: ../AnyBar.xcodeproj
33 | @xcodebuild -configuration Debug -target AnyBar -project $< build
34 |
35 | clean: ../AnyBar.xcodeproj
36 | -@xcodebuild -configuration Debug -target AnyBar -project $< clean 2>&1>/dev/null
37 | -@rm -rf ../build
38 |
39 | .PHONY: all tests anybar clean
40 |
41 | .SILENT: clean
42 |
43 |
--------------------------------------------------------------------------------
/AnyBar.xcodeproj/project.xcworkspace/xcshareddata/AnyBar.xccheckout:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDESourceControlProjectFavoriteDictionaryKey
6 |
7 | IDESourceControlProjectIdentifier
8 | BA23A1B6-5DAC-472E-A098-51AA9470648F
9 | IDESourceControlProjectName
10 | AnyBar
11 | IDESourceControlProjectOriginsDictionary
12 |
13 | 724AB094F6D42B778A94AB549935CA62FD6441E1
14 | github.com:tonsky/AnyBar.git
15 |
16 | IDESourceControlProjectPath
17 | AnyBar.xcodeproj
18 | IDESourceControlProjectRelativeInstallPathDictionary
19 |
20 | 724AB094F6D42B778A94AB549935CA62FD6441E1
21 | ../..
22 |
23 | IDESourceControlProjectURL
24 | github.com:tonsky/AnyBar.git
25 | IDESourceControlProjectVersion
26 | 111
27 | IDESourceControlProjectWCCIdentifier
28 | 724AB094F6D42B778A94AB549935CA62FD6441E1
29 | IDESourceControlProjectWCConfigurations
30 |
31 |
32 | IDESourceControlRepositoryExtensionIdentifierKey
33 | public.vcs.git
34 | IDESourceControlWCCIdentifierKey
35 | 724AB094F6D42B778A94AB549935CA62FD6441E1
36 | IDESourceControlWCCName
37 | AnyBar
38 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/AnyBar/AnyBar.sdef:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/AnyBar.xcodeproj/xcuserdata/prokopov.xcuserdatad/xcschemes/AnyBar.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
29 |
35 |
36 |
37 |
38 |
39 |
44 |
45 |
51 |
52 |
53 |
54 |
56 |
62 |
63 |
64 |
65 |
66 |
76 |
78 |
84 |
85 |
86 |
87 |
93 |
95 |
101 |
102 |
103 |
104 |
106 |
107 |
110 |
111 |
112 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # AnyBar: OS X menubar status indicator
2 |
3 | AnyBar is a small indicator for your menubar that does one simple thing: it displays a colored dot. What the dot means and when to change it is up to you.
4 |
5 |
6 |
7 | ## Download
8 |
9 | Version 0.2.3:
10 |
11 |
12 |
13 | Or using [Homebrew Cask](https://github.com/Homebrew/homebrew-cask):
14 |
15 | brew install --cask anybar
16 |
17 | ## Support us
18 |
19 |
20 |
21 | ## Usage
22 |
23 | AnyBar is controlled via a UDP port (1738 by default). Before any commands can be sent, AnyBar.app must be launched:
24 |
25 | ```sh
26 | open -a AnyBar
27 | ```
28 |
29 | Once launched, you may send it a message to change the style of the dot:
30 |
31 | ```sh
32 | echo -n "black" | nc -4u -w0 localhost 1738
33 | ```
34 |
35 | If you use bash, you might prefer this instead:
36 |
37 | ```sh
38 | bash -c 'echo -n "black" > /dev/udp/localhost/1738'
39 | ```
40 |
41 | The following default commands change the style of the dot:
42 |
43 | | Command | Preview |
44 | |---------------|---------------------------------------------------------------------|
45 | | `white` |
|
46 | | `red` |
|
47 | | `orange` |
|
48 | | `yellow` |
|
49 | | `green` |
|
50 | | `cyan` |
|
51 | | `blue` |
|
52 | | `purple` |
|
53 | | `black` |
|
54 | | `question` |
|
55 | | `exclamation` |
|
56 | | `filled` |
|
57 | | `hollow` |
|
58 |
59 | `black` and `white` always has black or white fill. On Big Sur, where text color of menubar might change depending on the wallpaper, you might want to use `filled` and `hollow` instead. They are inverted when menubar changes its appearance.
60 |
61 | To quit, send `quit`.
62 |
63 | ## Alternative clients
64 |
65 | Bash alias:
66 |
67 | ```sh
68 | $ function anybar { echo -n $1 | nc -4u -w0 localhost ${2:-1738}; }
69 |
70 | $ anybar red
71 | $ anybar green 1739
72 | ```
73 |
74 | Or with /dev/udp:
75 |
76 | ```sh
77 | function anybar { echo -n $1 > /dev/udp/localhost/${2:-1738}; }
78 | ```
79 |
80 | Zsh with completion:
81 |
82 | - [wookayin/anybar-zsh](https://github.com/wookayin/anybar-zsh)
83 |
84 | Fish shell with completion:
85 |
86 | - [matchai/anybar-fish](https://github.com/matchai/anybar-fish)
87 |
88 | Go:
89 |
90 | - [justincampbell/anybar](https://github.com/justincampbell/anybar)
91 | - [johntdyer/anybar-go](https://github.com/johntdyer/anybar-go)
92 |
93 | Node:
94 |
95 | - [rumpl/nanybar](https://github.com/rumpl/nanybar)
96 | - [sindresorhus/anybar](https://github.com/sindresorhus/anybar)
97 | - [snippet by skibz](https://github.com/tonsky/AnyBar/issues/11)
98 |
99 | Deno:
100 |
101 | - [pumpncode/anybar](https://github.com/pumpncode/anybar)
102 |
103 | PHP:
104 |
105 | - [2bj/Phanybar](https://github.com/2bj/Phanybar)
106 |
107 | Java:
108 |
109 | - [cs475x/AnyBar4j](https://github.com/cs475x/AnyBar4j)
110 |
111 | Python:
112 |
113 | - [philipbl/pyanybar](https://github.com/philipbl/pyAnyBar)
114 |
115 | Ruby:
116 |
117 | - [davydovanton/AnyBar_rb](https://github.com/davydovanton/AnyBar_rb)
118 |
119 | Rust:
120 |
121 | - [urschrei/rust_anybar](https://github.com/urschrei/rust_anybar)
122 | - [Feliix42/anybar-rs](https://github.com/Feliix42/anybar-rs)
123 |
124 | Nim:
125 |
126 | - [rgv151/anybar.nim](https://github.com/rgv151/anybar.nim)
127 |
128 | Erlang:
129 |
130 | - [kureikain/ebar](https://github.com/kureikain/ebar)
131 |
132 | C:
133 |
134 | - [onderweg/anybar-cli](https://github.com/onderweg/anybar-cli)
135 |
136 | C#:
137 |
138 | - [jenyayel/anybar-client](https://github.com/jenyayel/anybar-client)
139 |
140 | Crystal:
141 | - [davydovanton/AnyBar_cr](https://github.com/davydovanton/AnyBar_cr)
142 |
143 | Emacs:
144 |
145 | - [rmuslimov/anybar.el](https://gist.github.com/rmuslimov/2d74cacd5e0ae827663e)
146 | - [tie-rack/anybar-el](https://github.com/tie-rack/anybar-el) (Also on [Melpa](https://melpa.org/#/anybar))
147 |
148 | AppleScript:
149 |
150 | ```applescript
151 | tell application "AnyBar" to set image name to "blue"
152 |
153 | tell application "AnyBar" to set current to get image name as Unicode text
154 | display notification current
155 | ```
156 |
157 | Alfred:
158 |
159 | - [https://github.com/raguay/MyAlfred](https://github.com/raguay/MyAlfred/blob/master/Alfred%204/AnyBar%20Workflow.alfredworkflow)
160 |
161 | ## Integrations
162 |
163 | - Webpack build status plugin [roman01la/anybar-webpack](https://github.com/roman01la/anybar-webpack)
164 | - boot-clj task [tonsky/boot-anybar](https://github.com/tonsky/boot-anybar)
165 | - Idea plugin [denofevil/AnyBarIdea](https://github.com/denofevil/AnyBarIdea)
166 | - Anybar-based CLI journal [Andrew565/anybar-icon-journal](https://github.com/Andrew565/anybar-icon-journal)
167 | - Command monitoring [rvirani1/with_anybar](https://github.com/rvirani1/with_anybar)
168 | - Monitor commands automatically, across several iterm tabs [stacycurl/anybar_bash](https://github.com/stacycurl/anybar-bash)
169 | - Extension for ipython/jupyter/ipython notebook [ermakovpetr/ipython-anybar](https://github.com/ermakovpetr/ipython-anybar)
170 |
171 | ## Running multiple instances
172 |
173 | You can run several instances of AnyBar as long as they listen on different ports. Use the `ANYBAR_PORT` environment variable to change the port and `open -na` to run several instances:
174 |
175 | ```sh
176 | ANYBAR_PORT=1738 open -na AnyBar
177 | ANYBAR_PORT=1739 open -na AnyBar
178 | ANYBAR_PORT=1740 open -na AnyBar
179 | ```
180 |
181 | ## Environment variables to specify a title and the initial color of the dot
182 |
183 | A title can be set to distinguish dots in the menubar:
184 |
185 | ```sh
186 | ANYBAR_PORT=1738 ANYBAR_TITLE=First open -na AnyBar
187 | ANYBAR_PORT=1739 ANYBAR_TITLE=Second open -na AnyBar
188 | ANYBAR_PORT=1740 ANYBAR_TITLE=Third open -na AnyBar
189 | ```
190 |
191 | And the initial color of the dot can also be set:
192 |
193 | ```sh
194 | ANYBAR_INIT=blue open -na AnyBar
195 | ```
196 |
197 | ## Custom images
198 |
199 | AnyBar can detect and use local custom images stored in the `~/.AnyBar` directory. For example, if you have a `~/.AnyBar/square@2x.png` image, send `square` to port 1738 and it will be displayed. Images should be 19×19 pixels for standard resolution, and 38x38 pixels for retina (@2x).
200 |
201 | ## Ports
202 |
203 | - Ubuntu Unity [limpbrains/somebar](https://github.com/limpbrains/somebar)
204 | - i3wm with i3pystatus [enkore/i3pystatus](https://github.com/enkore/i3pystatus)
205 | - Windows 10 [PavelStefanov/NoteBar](https://github.com/PavelStefanov/NoteBar)
206 | - Emacs [plexus/.../emybar.el](https://github.com/plexus/plexmacs/blob/master/emybar/emybar.el)
207 |
208 | ## License
209 |
210 | Copyright © 2015 Nikita Prokopov
211 |
212 | Licensed under Eclipse Public License (see [LICENSE](LICENSE)).
213 |
--------------------------------------------------------------------------------
/AnyBar/AppDelegate.m:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.m
3 | // AnyBar
4 | //
5 | // Created by Nikita Prokopov on 14/02/15.
6 | // Copyright (c) 2015 Nikita Prokopov. All rights reserved.
7 | //
8 |
9 | #import "AppDelegate.h"
10 |
11 | @interface AppDelegate()
12 |
13 | @property (weak, nonatomic) IBOutlet NSWindow *window;
14 | @property (strong, nonatomic) NSStatusItem *statusItem;
15 | @property (strong, nonatomic) GCDAsyncUdpSocket *udpSocket;
16 | @property (strong, nonatomic) NSString *imageName;
17 | @property (assign, nonatomic) int udpPort;
18 | @property (assign, nonatomic) NSString *appTitle;
19 |
20 | @end
21 |
22 | @implementation AppDelegate
23 |
24 | -(void)applicationDidFinishLaunching:(NSNotification *)aNotification {
25 | _udpPort = -1;
26 | _imageName = [self readStringFromEnvironmentVariable:@"ANYBAR_INIT" usingDefault:@"hollow"];
27 | self.statusItem = [self initializeStatusBarItem];
28 | [self setImage:_imageName];
29 |
30 | @try {
31 | _udpPort = [self getUdpPort];
32 | _udpSocket = [self initializeUdpSocket: _udpPort];
33 | _appTitle = [self readStringFromEnvironmentVariable:@"ANYBAR_TITLE" usingDefault:nil];
34 | _statusItem.toolTip = _appTitle == nil ? [NSString stringWithFormat:@"AnyBar @ %d", _udpPort] : _appTitle;
35 | }
36 | @catch(NSException *ex) {
37 | NSLog(@"Error: %@: %@", ex.name, ex.reason);
38 | _statusItem.image = [NSImage imageNamed:@"exclamation@2x.png"];
39 | [_statusItem.image setTemplate:NO];
40 | }
41 | @finally {
42 | NSString *portTitle = [NSString stringWithFormat:@"UDP port: %@", _udpPort >= 0 ? [NSNumber numberWithInt:_udpPort] : @"unavailable"];
43 | NSMenu *menu = [[NSMenu alloc] init];
44 |
45 | if (_appTitle != nil)
46 | [menu addItemWithTitle:_appTitle action:nil keyEquivalent:@""];
47 | [menu addItemWithTitle:portTitle action:nil keyEquivalent:@""];
48 | [menu addItemWithTitle:@"Quit" action:@selector(terminate:) keyEquivalent:@""];
49 |
50 | _statusItem.menu = menu;
51 | }
52 | }
53 |
54 | -(void)applicationWillTerminate:(NSNotification *)aNotification {
55 | [self shutdownUdpSocket: _udpSocket];
56 | _udpSocket = nil;
57 |
58 | [[NSStatusBar systemStatusBar] removeStatusItem:_statusItem];
59 | _statusItem = nil;
60 | }
61 |
62 | -(int) getUdpPort {
63 | int port = [self readIntFromEnvironmentVariable:@"ANYBAR_PORT" usingDefault:@"1738"];
64 |
65 | if (port < 0 || port > 65535) {
66 | @throw([NSException exceptionWithName:@"Argument Exception"
67 | reason:[NSString stringWithFormat:@"UDP Port range is invalid: %d", port]
68 | userInfo:@{@"argument": [NSNumber numberWithInt:port]}]);
69 |
70 | }
71 |
72 | return port;
73 | }
74 |
75 | -(GCDAsyncUdpSocket*)initializeUdpSocket:(int)port {
76 | NSError *error = nil;
77 | GCDAsyncUdpSocket *udpSocket = [[GCDAsyncUdpSocket alloc]
78 | initWithDelegate:self
79 | delegateQueue:dispatch_get_main_queue()];
80 |
81 | [udpSocket bindToPort:port error:&error];
82 | if (error) {
83 | @throw([NSException exceptionWithName:@"UDP Exception"
84 | reason:[NSString stringWithFormat:@"Binding to %d failed", port]
85 | userInfo:@{@"error": error}]);
86 | }
87 |
88 | [udpSocket beginReceiving:&error];
89 | if (error) {
90 | @throw([NSException exceptionWithName:@"UDP Exception"
91 | reason:[NSString stringWithFormat:@"Receiving from %d failed", port]
92 | userInfo:@{@"error": error}]);
93 | }
94 |
95 | return udpSocket;
96 | }
97 |
98 | -(void)shutdownUdpSocket:(GCDAsyncUdpSocket*)sock {
99 | if (sock != nil) {
100 | [sock close];
101 | }
102 | }
103 |
104 | -(void)udpSocket:(GCDAsyncUdpSocket *)sock didReceiveData:(NSData *)data
105 | fromAddress:(NSData *)address withFilterContext:(id)filterContext {
106 | [self processUdpSocketMsg:sock withData:data fromAddress:address];
107 | }
108 |
109 | -(NSImage*)tryImage:(NSString *)path {
110 | NSFileManager *fileManager = [NSFileManager defaultManager];
111 | if ([fileManager fileExistsAtPath:path])
112 | return [[NSImage alloc] initWithContentsOfFile:path];
113 | else
114 | return nil;
115 | }
116 |
117 | -(NSString*)bundledImagePath:(NSString *)name {
118 | return [[NSBundle mainBundle] pathForResource:name ofType:@"png"];
119 | }
120 |
121 | -(NSString*)homedirImagePath:(NSString *)name {
122 | return [NSString stringWithFormat:@"%@/%@/%@.png", NSHomeDirectory(), @".AnyBar", name];
123 | }
124 |
125 | -(void)setImage:(NSString*) name {
126 | NSImage *image = nil;
127 | image = [self tryImage:[self homedirImagePath:[name stringByAppendingString:@"@2x"]]];
128 | if (!image)
129 | image = [self tryImage:[self homedirImagePath:name]];
130 | if (!image)
131 | image = [self tryImage:[self bundledImagePath:[name stringByAppendingString:@"@2x"]]];
132 | if (!image)
133 | image = [self tryImage:[self bundledImagePath:name]];
134 | if (!image) {
135 | NSLog(@"Cannot find image '%@'", name);
136 | image = [self tryImage:[self bundledImagePath:@"question@2x"]];
137 | _statusItem.image = image;
138 | [_statusItem.image setTemplate:NO];
139 | } else {
140 | _statusItem.image = image;
141 | if ([name isEqualToString:@"filled"] || [name isEqualToString:@"hollow"])
142 | [_statusItem.image setTemplate:YES];
143 | else
144 | [_statusItem.image setTemplate:NO];
145 | _imageName = name;
146 | }
147 | }
148 |
149 | -(void)processUdpSocketMsg:(GCDAsyncUdpSocket *)sock withData:(NSData *)data
150 | fromAddress:(NSData *)address {
151 | NSString *msg = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
152 |
153 | if ([msg isEqualToString:@"quit"])
154 | [[NSApplication sharedApplication] terminate:nil];
155 | else
156 | [self setImage:msg];
157 | }
158 |
159 | -(NSStatusItem*) initializeStatusBarItem {
160 | NSStatusItem *statusItem = [[NSStatusBar systemStatusBar] statusItemWithLength:NSVariableStatusItemLength];
161 | // statusItem.image = [NSImage imageNamed:@"white@2x.png"];
162 | statusItem.highlightMode = YES;
163 | return statusItem;
164 | }
165 |
166 | -(int) readIntFromEnvironmentVariable:(NSString*) envVariable usingDefault:(NSString*) defStr {
167 | int intVal = -1;
168 |
169 | NSString *envStr = [[[NSProcessInfo processInfo]
170 | environment] objectForKey:envVariable];
171 | if (!envStr) {
172 | envStr = defStr;
173 | }
174 |
175 | NSNumberFormatter *nFormatter = [[NSNumberFormatter alloc] init];
176 | nFormatter.numberStyle = NSNumberFormatterDecimalStyle;
177 | NSNumber *number = [nFormatter numberFromString:envStr];
178 |
179 | if (!number) {
180 | @throw([NSException exceptionWithName:@"Argument Exception"
181 | reason:[NSString stringWithFormat:@"Parsing integer from %@ failed", envStr]
182 | userInfo:@{@"argument": envStr}]);
183 |
184 | }
185 |
186 | intVal = [number intValue];
187 |
188 | return intVal;
189 | }
190 |
191 | -(NSString*) readStringFromEnvironmentVariable:(NSString*) envVariable usingDefault:(NSString*) defStr {
192 | NSString *envStr = [[[NSProcessInfo processInfo]
193 | environment] objectForKey:envVariable];
194 |
195 | if (!envStr) {
196 | envStr = defStr;
197 | }
198 |
199 | return envStr;
200 | }
201 |
202 | -(id) osaImageBridge {
203 | NSLog(@"OSA Event: %@ - %@", NSStringFromSelector(_cmd), _imageName);
204 |
205 | return _imageName;
206 | }
207 |
208 |
209 | -(void) setOsaImageBridge:(id)imgName {
210 | NSLog(@"OSA Event: %@ - %@", NSStringFromSelector(_cmd), imgName);
211 |
212 | _imageName = (NSString *)imgName;
213 |
214 | [self setImage:_imageName];
215 | }
216 |
217 | @end
218 |
219 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Eclipse Public License - v 1.0
2 |
3 | THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC
4 | LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM
5 | CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT.
6 |
7 | 1. DEFINITIONS
8 |
9 | "Contribution" means:
10 |
11 | a) in the case of the initial Contributor, the initial code and documentation
12 | distributed under this Agreement, and
13 | b) in the case of each subsequent Contributor:
14 | i) changes to the Program, and
15 | ii) additions to the Program;
16 |
17 | where such changes and/or additions to the Program originate from and are
18 | distributed by that particular Contributor. A Contribution 'originates'
19 | from a Contributor if it was added to the Program by such Contributor
20 | itself or anyone acting on such Contributor's behalf. Contributions do not
21 | include additions to the Program which: (i) are separate modules of
22 | software distributed in conjunction with the Program under their own
23 | license agreement, and (ii) are not derivative works of the Program.
24 |
25 | "Contributor" means any person or entity that distributes the Program.
26 |
27 | "Licensed Patents" mean patent claims licensable by a Contributor which are
28 | necessarily infringed by the use or sale of its Contribution alone or when
29 | combined with the Program.
30 |
31 | "Program" means the Contributions distributed in accordance with this
32 | Agreement.
33 |
34 | "Recipient" means anyone who receives the Program under this Agreement,
35 | including all Contributors.
36 |
37 | 2. GRANT OF RIGHTS
38 | a) Subject to the terms of this Agreement, each Contributor hereby grants
39 | Recipient a non-exclusive, worldwide, royalty-free copyright license to
40 | reproduce, prepare derivative works of, publicly display, publicly
41 | perform, distribute and sublicense the Contribution of such Contributor,
42 | if any, and such derivative works, in source code and object code form.
43 | b) Subject to the terms of this Agreement, each Contributor hereby grants
44 | Recipient a non-exclusive, worldwide, royalty-free patent license under
45 | Licensed Patents to make, use, sell, offer to sell, import and otherwise
46 | transfer the Contribution of such Contributor, if any, in source code and
47 | object code form. This patent license shall apply to the combination of
48 | the Contribution and the Program if, at the time the Contribution is
49 | added by the Contributor, such addition of the Contribution causes such
50 | combination to be covered by the Licensed Patents. The patent license
51 | shall not apply to any other combinations which include the Contribution.
52 | No hardware per se is licensed hereunder.
53 | c) Recipient understands that although each Contributor grants the licenses
54 | to its Contributions set forth herein, no assurances are provided by any
55 | Contributor that the Program does not infringe the patent or other
56 | intellectual property rights of any other entity. Each Contributor
57 | disclaims any liability to Recipient for claims brought by any other
58 | entity based on infringement of intellectual property rights or
59 | otherwise. As a condition to exercising the rights and licenses granted
60 | hereunder, each Recipient hereby assumes sole responsibility to secure
61 | any other intellectual property rights needed, if any. For example, if a
62 | third party patent license is required to allow Recipient to distribute
63 | the Program, it is Recipient's responsibility to acquire that license
64 | before distributing the Program.
65 | d) Each Contributor represents that to its knowledge it has sufficient
66 | copyright rights in its Contribution, if any, to grant the copyright
67 | license set forth in this Agreement.
68 |
69 | 3. REQUIREMENTS
70 |
71 | A Contributor may choose to distribute the Program in object code form under
72 | its own license agreement, provided that:
73 |
74 | a) it complies with the terms and conditions of this Agreement; and
75 | b) its license agreement:
76 | i) effectively disclaims on behalf of all Contributors all warranties
77 | and conditions, express and implied, including warranties or
78 | conditions of title and non-infringement, and implied warranties or
79 | conditions of merchantability and fitness for a particular purpose;
80 | ii) effectively excludes on behalf of all Contributors all liability for
81 | damages, including direct, indirect, special, incidental and
82 | consequential damages, such as lost profits;
83 | iii) states that any provisions which differ from this Agreement are
84 | offered by that Contributor alone and not by any other party; and
85 | iv) states that source code for the Program is available from such
86 | Contributor, and informs licensees how to obtain it in a reasonable
87 | manner on or through a medium customarily used for software exchange.
88 |
89 | When the Program is made available in source code form:
90 |
91 | a) it must be made available under this Agreement; and
92 | b) a copy of this Agreement must be included with each copy of the Program.
93 | Contributors may not remove or alter any copyright notices contained
94 | within the Program.
95 |
96 | Each Contributor must identify itself as the originator of its Contribution,
97 | if
98 | any, in a manner that reasonably allows subsequent Recipients to identify the
99 | originator of the Contribution.
100 |
101 | 4. COMMERCIAL DISTRIBUTION
102 |
103 | Commercial distributors of software may accept certain responsibilities with
104 | respect to end users, business partners and the like. While this license is
105 | intended to facilitate the commercial use of the Program, the Contributor who
106 | includes the Program in a commercial product offering should do so in a manner
107 | which does not create potential liability for other Contributors. Therefore,
108 | if a Contributor includes the Program in a commercial product offering, such
109 | Contributor ("Commercial Contributor") hereby agrees to defend and indemnify
110 | every other Contributor ("Indemnified Contributor") against any losses,
111 | damages and costs (collectively "Losses") arising from claims, lawsuits and
112 | other legal actions brought by a third party against the Indemnified
113 | Contributor to the extent caused by the acts or omissions of such Commercial
114 | Contributor in connection with its distribution of the Program in a commercial
115 | product offering. The obligations in this section do not apply to any claims
116 | or Losses relating to any actual or alleged intellectual property
117 | infringement. In order to qualify, an Indemnified Contributor must:
118 | a) promptly notify the Commercial Contributor in writing of such claim, and
119 | b) allow the Commercial Contributor to control, and cooperate with the
120 | Commercial Contributor in, the defense and any related settlement
121 | negotiations. The Indemnified Contributor may participate in any such claim at
122 | its own expense.
123 |
124 | For example, a Contributor might include the Program in a commercial product
125 | offering, Product X. That Contributor is then a Commercial Contributor. If
126 | that Commercial Contributor then makes performance claims, or offers
127 | warranties related to Product X, those performance claims and warranties are
128 | such Commercial Contributor's responsibility alone. Under this section, the
129 | Commercial Contributor would have to defend claims against the other
130 | Contributors related to those performance claims and warranties, and if a
131 | court requires any other Contributor to pay any damages as a result, the
132 | Commercial Contributor must pay those damages.
133 |
134 | 5. NO WARRANTY
135 |
136 | EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED ON AN
137 | "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR
138 | IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE,
139 | NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each
140 | Recipient is solely responsible for determining the appropriateness of using
141 | and distributing the Program and assumes all risks associated with its
142 | exercise of rights under this Agreement , including but not limited to the
143 | risks and costs of program errors, compliance with applicable laws, damage to
144 | or loss of data, programs or equipment, and unavailability or interruption of
145 | operations.
146 |
147 | 6. DISCLAIMER OF LIABILITY
148 |
149 | EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY
150 | CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL,
151 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION
152 | LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
153 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
154 | ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE
155 | EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY
156 | OF SUCH DAMAGES.
157 |
158 | 7. GENERAL
159 |
160 | If any provision of this Agreement is invalid or unenforceable under
161 | applicable law, it shall not affect the validity or enforceability of the
162 | remainder of the terms of this Agreement, and without further action by the
163 | parties hereto, such provision shall be reformed to the minimum extent
164 | necessary to make such provision valid and enforceable.
165 |
166 | If Recipient institutes patent litigation against any entity (including a
167 | cross-claim or counterclaim in a lawsuit) alleging that the Program itself
168 | (excluding combinations of the Program with other software or hardware)
169 | infringes such Recipient's patent(s), then such Recipient's rights granted
170 | under Section 2(b) shall terminate as of the date such litigation is filed.
171 |
172 | All Recipient's rights under this Agreement shall terminate if it fails to
173 | comply with any of the material terms or conditions of this Agreement and does
174 | not cure such failure in a reasonable period of time after becoming aware of
175 | such noncompliance. If all Recipient's rights under this Agreement terminate,
176 | Recipient agrees to cease use and distribution of the Program as soon as
177 | reasonably practicable. However, Recipient's obligations under this Agreement
178 | and any licenses granted by Recipient relating to the Program shall continue
179 | and survive.
180 |
181 | Everyone is permitted to copy and distribute copies of this Agreement, but in
182 | order to avoid inconsistency the Agreement is copyrighted and may only be
183 | modified in the following manner. The Agreement Steward reserves the right to
184 | publish new versions (including revisions) of this Agreement from time to
185 | time. No one other than the Agreement Steward has the right to modify this
186 | Agreement. The Eclipse Foundation is the initial Agreement Steward. The
187 | Eclipse Foundation may assign the responsibility to serve as the Agreement
188 | Steward to a suitable separate entity. Each new version of the Agreement will
189 | be given a distinguishing version number. The Program (including
190 | Contributions) may always be distributed subject to the version of the
191 | Agreement under which it was received. In addition, after a new version of the
192 | Agreement is published, Contributor may elect to distribute the Program
193 | (including its Contributions) under the new version. Except as expressly
194 | stated in Sections 2(a) and 2(b) above, Recipient receives no rights or
195 | licenses to the intellectual property of any Contributor under this Agreement,
196 | whether expressly, by implication, estoppel or otherwise. All rights in the
197 | Program not expressly granted under this Agreement are reserved.
198 |
199 | This Agreement is governed by the laws of the State of New York and the
200 | intellectual property laws of the United States of America. No party to this
201 | Agreement will bring a legal action under this Agreement more than one year
202 | after the cause of action arose. Each party waives its rights to a jury trial in
203 | any resulting litigation.
204 |
205 |
--------------------------------------------------------------------------------
/AnyBar.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 46;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 7648BAC31AA5A50B003DA28F /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = C5AB32C41A8F9091002258B6 /* MainMenu.xib */; };
11 | C03A3D3E1AA78DAD0030B668 /* AnyBar.sdef in Resources */ = {isa = PBXBuildFile; fileRef = C03A3D3D1AA78DAD0030B668 /* AnyBar.sdef */; };
12 | C03A3D431AA7A6540030B668 /* AnyBarApp.m in Sources */ = {isa = PBXBuildFile; fileRef = C03A3D421AA7A6540030B668 /* AnyBarApp.m */; };
13 | C504CCFB25DEE28400DDEE71 /* filled@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = C504CCF925DEE28400DDEE71 /* filled@2x.png */; };
14 | C504CCFC25DEE28400DDEE71 /* hollow@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = C504CCFA25DEE28400DDEE71 /* hollow@2x.png */; };
15 | C5AB32BF1A8F9091002258B6 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = C5AB32BE1A8F9091002258B6 /* AppDelegate.m */; };
16 | C5AB32C11A8F9091002258B6 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = C5AB32C01A8F9091002258B6 /* main.m */; };
17 | C5AB32C31A8F9091002258B6 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = C5AB32C21A8F9091002258B6 /* Images.xcassets */; };
18 | C5AB32E71A8F9B4E002258B6 /* GCDAsyncSocket.m in Sources */ = {isa = PBXBuildFile; fileRef = C5AB32E41A8F9B4E002258B6 /* GCDAsyncSocket.m */; };
19 | C5AB32E81A8F9B4E002258B6 /* GCDAsyncUdpSocket.m in Sources */ = {isa = PBXBuildFile; fileRef = C5AB32E61A8F9B4E002258B6 /* GCDAsyncUdpSocket.m */; };
20 | C5E0271E1AA6435E0032F2E9 /* black@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = C5E027111AA6435E0032F2E9 /* black@2x.png */; };
21 | C5E0271F1AA6435E0032F2E9 /* blue@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = C5E027121AA6435E0032F2E9 /* blue@2x.png */; };
22 | C5E027201AA6435E0032F2E9 /* cyan@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = C5E027131AA6435E0032F2E9 /* cyan@2x.png */; };
23 | C5E027211AA6435E0032F2E9 /* green@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = C5E027141AA6435E0032F2E9 /* green@2x.png */; };
24 | C5E027221AA6435E0032F2E9 /* orange@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = C5E027151AA6435E0032F2E9 /* orange@2x.png */; };
25 | C5E027231AA6435E0032F2E9 /* purple@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = C5E027161AA6435E0032F2E9 /* purple@2x.png */; };
26 | C5E027241AA6435E0032F2E9 /* red@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = C5E027171AA6435E0032F2E9 /* red@2x.png */; };
27 | C5E027281AA6435E0032F2E9 /* white@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = C5E0271B1AA6435E0032F2E9 /* white@2x.png */; };
28 | C5E027291AA6435E0032F2E9 /* yellow@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = C5E0271C1AA6435E0032F2E9 /* yellow@2x.png */; };
29 | C5E0272F1AA64BD90032F2E9 /* exclamation@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = C5E0272C1AA64BD90032F2E9 /* exclamation@2x.png */; };
30 | C5E027311AA64BD90032F2E9 /* question@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = C5E0272E1AA64BD90032F2E9 /* question@2x.png */; };
31 | /* End PBXBuildFile section */
32 |
33 | /* Begin PBXFileReference section */
34 | C03A3D3D1AA78DAD0030B668 /* AnyBar.sdef */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = AnyBar.sdef; sourceTree = ""; };
35 | C03A3D411AA7A6540030B668 /* AnyBarApp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AnyBarApp.h; sourceTree = ""; };
36 | C03A3D421AA7A6540030B668 /* AnyBarApp.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AnyBarApp.m; sourceTree = ""; };
37 | C504CCF925DEE28400DDEE71 /* filled@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "filled@2x.png"; sourceTree = ""; };
38 | C504CCFA25DEE28400DDEE71 /* hollow@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "hollow@2x.png"; sourceTree = ""; };
39 | C511DFFB1AA4E9CF00DEE15F /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; };
40 | C5AB32B81A8F9091002258B6 /* AnyBar.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = AnyBar.app; sourceTree = BUILT_PRODUCTS_DIR; };
41 | C5AB32BC1A8F9091002258B6 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
42 | C5AB32BD1A8F9091002258B6 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; };
43 | C5AB32BE1A8F9091002258B6 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; };
44 | C5AB32C01A8F9091002258B6 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; };
45 | C5AB32C21A8F9091002258B6 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; };
46 | C5AB32C51A8F9091002258B6 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; };
47 | C5AB32E31A8F9B4E002258B6 /* GCDAsyncSocket.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GCDAsyncSocket.h; sourceTree = ""; };
48 | C5AB32E41A8F9B4E002258B6 /* GCDAsyncSocket.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GCDAsyncSocket.m; sourceTree = ""; };
49 | C5AB32E51A8F9B4E002258B6 /* GCDAsyncUdpSocket.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GCDAsyncUdpSocket.h; sourceTree = ""; };
50 | C5AB32E61A8F9B4E002258B6 /* GCDAsyncUdpSocket.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GCDAsyncUdpSocket.m; sourceTree = ""; };
51 | C5E027111AA6435E0032F2E9 /* black@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "black@2x.png"; sourceTree = ""; };
52 | C5E027121AA6435E0032F2E9 /* blue@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "blue@2x.png"; sourceTree = ""; };
53 | C5E027131AA6435E0032F2E9 /* cyan@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "cyan@2x.png"; sourceTree = ""; };
54 | C5E027141AA6435E0032F2E9 /* green@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "green@2x.png"; sourceTree = ""; };
55 | C5E027151AA6435E0032F2E9 /* orange@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "orange@2x.png"; sourceTree = ""; };
56 | C5E027161AA6435E0032F2E9 /* purple@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "purple@2x.png"; sourceTree = ""; };
57 | C5E027171AA6435E0032F2E9 /* red@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "red@2x.png"; sourceTree = ""; };
58 | C5E0271B1AA6435E0032F2E9 /* white@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "white@2x.png"; sourceTree = ""; };
59 | C5E0271C1AA6435E0032F2E9 /* yellow@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "yellow@2x.png"; sourceTree = ""; };
60 | C5E0272C1AA64BD90032F2E9 /* exclamation@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "exclamation@2x.png"; sourceTree = ""; };
61 | C5E0272E1AA64BD90032F2E9 /* question@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "question@2x.png"; sourceTree = ""; };
62 | /* End PBXFileReference section */
63 |
64 | /* Begin PBXFrameworksBuildPhase section */
65 | C5AB32B51A8F9091002258B6 /* Frameworks */ = {
66 | isa = PBXFrameworksBuildPhase;
67 | buildActionMask = 2147483647;
68 | files = (
69 | );
70 | runOnlyForDeploymentPostprocessing = 0;
71 | };
72 | /* End PBXFrameworksBuildPhase section */
73 |
74 | /* Begin PBXGroup section */
75 | 7648BAAC1AA5A3C0003DA28F /* Resources */ = {
76 | isa = PBXGroup;
77 | children = (
78 | C504CCF925DEE28400DDEE71 /* filled@2x.png */,
79 | C504CCFA25DEE28400DDEE71 /* hollow@2x.png */,
80 | C5E0272C1AA64BD90032F2E9 /* exclamation@2x.png */,
81 | C5E0272E1AA64BD90032F2E9 /* question@2x.png */,
82 | C5E027111AA6435E0032F2E9 /* black@2x.png */,
83 | C5E027121AA6435E0032F2E9 /* blue@2x.png */,
84 | C5E027131AA6435E0032F2E9 /* cyan@2x.png */,
85 | C5E027141AA6435E0032F2E9 /* green@2x.png */,
86 | C5E027151AA6435E0032F2E9 /* orange@2x.png */,
87 | C5E027161AA6435E0032F2E9 /* purple@2x.png */,
88 | C5E027171AA6435E0032F2E9 /* red@2x.png */,
89 | C5E0271B1AA6435E0032F2E9 /* white@2x.png */,
90 | C5E0271C1AA6435E0032F2E9 /* yellow@2x.png */,
91 | );
92 | path = Resources;
93 | sourceTree = "";
94 | };
95 | C5AB32AF1A8F9091002258B6 = {
96 | isa = PBXGroup;
97 | children = (
98 | C5AB32BA1A8F9091002258B6 /* AnyBar */,
99 | C5AB32B91A8F9091002258B6 /* Products */,
100 | C511DFFB1AA4E9CF00DEE15F /* README.md */,
101 | );
102 | sourceTree = "";
103 | };
104 | C5AB32B91A8F9091002258B6 /* Products */ = {
105 | isa = PBXGroup;
106 | children = (
107 | C5AB32B81A8F9091002258B6 /* AnyBar.app */,
108 | );
109 | name = Products;
110 | sourceTree = "";
111 | };
112 | C5AB32BA1A8F9091002258B6 /* AnyBar */ = {
113 | isa = PBXGroup;
114 | children = (
115 | C5AB32E31A8F9B4E002258B6 /* GCDAsyncSocket.h */,
116 | C5AB32E41A8F9B4E002258B6 /* GCDAsyncSocket.m */,
117 | C5AB32E51A8F9B4E002258B6 /* GCDAsyncUdpSocket.h */,
118 | C5AB32E61A8F9B4E002258B6 /* GCDAsyncUdpSocket.m */,
119 | C5AB32BD1A8F9091002258B6 /* AppDelegate.h */,
120 | C5AB32BE1A8F9091002258B6 /* AppDelegate.m */,
121 | C03A3D411AA7A6540030B668 /* AnyBarApp.h */,
122 | C03A3D421AA7A6540030B668 /* AnyBarApp.m */,
123 | C5AB32C21A8F9091002258B6 /* Images.xcassets */,
124 | C5AB32C41A8F9091002258B6 /* MainMenu.xib */,
125 | 7648BAAC1AA5A3C0003DA28F /* Resources */,
126 | C5AB32BB1A8F9091002258B6 /* Supporting Files */,
127 | );
128 | path = AnyBar;
129 | sourceTree = "";
130 | };
131 | C5AB32BB1A8F9091002258B6 /* Supporting Files */ = {
132 | isa = PBXGroup;
133 | children = (
134 | C03A3D3D1AA78DAD0030B668 /* AnyBar.sdef */,
135 | C5AB32BC1A8F9091002258B6 /* Info.plist */,
136 | C5AB32C01A8F9091002258B6 /* main.m */,
137 | );
138 | name = "Supporting Files";
139 | sourceTree = "";
140 | };
141 | /* End PBXGroup section */
142 |
143 | /* Begin PBXNativeTarget section */
144 | C5AB32B71A8F9091002258B6 /* AnyBar */ = {
145 | isa = PBXNativeTarget;
146 | buildConfigurationList = C5AB32D51A8F9091002258B6 /* Build configuration list for PBXNativeTarget "AnyBar" */;
147 | buildPhases = (
148 | C5AB32B41A8F9091002258B6 /* Sources */,
149 | C5AB32B51A8F9091002258B6 /* Frameworks */,
150 | C5AB32B61A8F9091002258B6 /* Resources */,
151 | );
152 | buildRules = (
153 | );
154 | dependencies = (
155 | );
156 | name = AnyBar;
157 | productName = AnyBar;
158 | productReference = C5AB32B81A8F9091002258B6 /* AnyBar.app */;
159 | productType = "com.apple.product-type.application";
160 | };
161 | /* End PBXNativeTarget section */
162 |
163 | /* Begin PBXProject section */
164 | C5AB32B01A8F9091002258B6 /* Project object */ = {
165 | isa = PBXProject;
166 | attributes = {
167 | LastUpgradeCheck = 0810;
168 | ORGANIZATIONNAME = "Nikita Prokopov";
169 | TargetAttributes = {
170 | C5AB32B71A8F9091002258B6 = {
171 | CreatedOnToolsVersion = 6.1.1;
172 | };
173 | };
174 | };
175 | buildConfigurationList = C5AB32B31A8F9091002258B6 /* Build configuration list for PBXProject "AnyBar" */;
176 | compatibilityVersion = "Xcode 3.2";
177 | developmentRegion = English;
178 | hasScannedForEncodings = 0;
179 | knownRegions = (
180 | English,
181 | en,
182 | Base,
183 | );
184 | mainGroup = C5AB32AF1A8F9091002258B6;
185 | productRefGroup = C5AB32B91A8F9091002258B6 /* Products */;
186 | projectDirPath = "";
187 | projectRoot = "";
188 | targets = (
189 | C5AB32B71A8F9091002258B6 /* AnyBar */,
190 | );
191 | };
192 | /* End PBXProject section */
193 |
194 | /* Begin PBXResourcesBuildPhase section */
195 | C5AB32B61A8F9091002258B6 /* Resources */ = {
196 | isa = PBXResourcesBuildPhase;
197 | buildActionMask = 2147483647;
198 | files = (
199 | C5E027241AA6435E0032F2E9 /* red@2x.png in Resources */,
200 | C5E027231AA6435E0032F2E9 /* purple@2x.png in Resources */,
201 | C5AB32C31A8F9091002258B6 /* Images.xcassets in Resources */,
202 | C5E027291AA6435E0032F2E9 /* yellow@2x.png in Resources */,
203 | C5E027311AA64BD90032F2E9 /* question@2x.png in Resources */,
204 | C5E027281AA6435E0032F2E9 /* white@2x.png in Resources */,
205 | 7648BAC31AA5A50B003DA28F /* MainMenu.xib in Resources */,
206 | C5E027211AA6435E0032F2E9 /* green@2x.png in Resources */,
207 | C5E0272F1AA64BD90032F2E9 /* exclamation@2x.png in Resources */,
208 | C5E0271E1AA6435E0032F2E9 /* black@2x.png in Resources */,
209 | C5E027201AA6435E0032F2E9 /* cyan@2x.png in Resources */,
210 | C504CCFB25DEE28400DDEE71 /* filled@2x.png in Resources */,
211 | C5E0271F1AA6435E0032F2E9 /* blue@2x.png in Resources */,
212 | C5E027221AA6435E0032F2E9 /* orange@2x.png in Resources */,
213 | C03A3D3E1AA78DAD0030B668 /* AnyBar.sdef in Resources */,
214 | C504CCFC25DEE28400DDEE71 /* hollow@2x.png in Resources */,
215 | );
216 | runOnlyForDeploymentPostprocessing = 0;
217 | };
218 | /* End PBXResourcesBuildPhase section */
219 |
220 | /* Begin PBXSourcesBuildPhase section */
221 | C5AB32B41A8F9091002258B6 /* Sources */ = {
222 | isa = PBXSourcesBuildPhase;
223 | buildActionMask = 2147483647;
224 | files = (
225 | C03A3D431AA7A6540030B668 /* AnyBarApp.m in Sources */,
226 | C5AB32E81A8F9B4E002258B6 /* GCDAsyncUdpSocket.m in Sources */,
227 | C5AB32E71A8F9B4E002258B6 /* GCDAsyncSocket.m in Sources */,
228 | C5AB32C11A8F9091002258B6 /* main.m in Sources */,
229 | C5AB32BF1A8F9091002258B6 /* AppDelegate.m in Sources */,
230 | );
231 | runOnlyForDeploymentPostprocessing = 0;
232 | };
233 | /* End PBXSourcesBuildPhase section */
234 |
235 | /* Begin PBXVariantGroup section */
236 | C5AB32C41A8F9091002258B6 /* MainMenu.xib */ = {
237 | isa = PBXVariantGroup;
238 | children = (
239 | C5AB32C51A8F9091002258B6 /* Base */,
240 | );
241 | name = MainMenu.xib;
242 | sourceTree = "";
243 | };
244 | /* End PBXVariantGroup section */
245 |
246 | /* Begin XCBuildConfiguration section */
247 | C5AB32D31A8F9091002258B6 /* Debug */ = {
248 | isa = XCBuildConfiguration;
249 | buildSettings = {
250 | ALWAYS_SEARCH_USER_PATHS = NO;
251 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
252 | CLANG_CXX_LIBRARY = "libc++";
253 | CLANG_ENABLE_MODULES = YES;
254 | CLANG_ENABLE_OBJC_ARC = YES;
255 | CLANG_WARN_BOOL_CONVERSION = YES;
256 | CLANG_WARN_CONSTANT_CONVERSION = YES;
257 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
258 | CLANG_WARN_EMPTY_BODY = YES;
259 | CLANG_WARN_ENUM_CONVERSION = YES;
260 | CLANG_WARN_INFINITE_RECURSION = YES;
261 | CLANG_WARN_INT_CONVERSION = YES;
262 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
263 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
264 | CLANG_WARN_UNREACHABLE_CODE = YES;
265 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
266 | CODE_SIGN_IDENTITY = "-";
267 | COPY_PHASE_STRIP = NO;
268 | ENABLE_STRICT_OBJC_MSGSEND = YES;
269 | ENABLE_TESTABILITY = YES;
270 | GCC_C_LANGUAGE_STANDARD = gnu99;
271 | GCC_DYNAMIC_NO_PIC = NO;
272 | GCC_NO_COMMON_BLOCKS = YES;
273 | GCC_OPTIMIZATION_LEVEL = 0;
274 | GCC_PREPROCESSOR_DEFINITIONS = (
275 | "DEBUG=1",
276 | "$(inherited)",
277 | );
278 | GCC_SYMBOLS_PRIVATE_EXTERN = NO;
279 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
280 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
281 | GCC_WARN_UNDECLARED_SELECTOR = YES;
282 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
283 | GCC_WARN_UNUSED_FUNCTION = YES;
284 | GCC_WARN_UNUSED_VARIABLE = YES;
285 | MACOSX_DEPLOYMENT_TARGET = 10.9;
286 | MTL_ENABLE_DEBUG_INFO = YES;
287 | ONLY_ACTIVE_ARCH = YES;
288 | SDKROOT = macosx;
289 | };
290 | name = Debug;
291 | };
292 | C5AB32D41A8F9091002258B6 /* Release */ = {
293 | isa = XCBuildConfiguration;
294 | buildSettings = {
295 | ALWAYS_SEARCH_USER_PATHS = NO;
296 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
297 | CLANG_CXX_LIBRARY = "libc++";
298 | CLANG_ENABLE_MODULES = YES;
299 | CLANG_ENABLE_OBJC_ARC = YES;
300 | CLANG_WARN_BOOL_CONVERSION = YES;
301 | CLANG_WARN_CONSTANT_CONVERSION = YES;
302 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
303 | CLANG_WARN_EMPTY_BODY = YES;
304 | CLANG_WARN_ENUM_CONVERSION = YES;
305 | CLANG_WARN_INFINITE_RECURSION = YES;
306 | CLANG_WARN_INT_CONVERSION = YES;
307 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
308 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
309 | CLANG_WARN_UNREACHABLE_CODE = YES;
310 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
311 | CODE_SIGN_IDENTITY = "-";
312 | COPY_PHASE_STRIP = YES;
313 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
314 | ENABLE_NS_ASSERTIONS = NO;
315 | ENABLE_STRICT_OBJC_MSGSEND = YES;
316 | GCC_C_LANGUAGE_STANDARD = gnu99;
317 | GCC_NO_COMMON_BLOCKS = YES;
318 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
319 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
320 | GCC_WARN_UNDECLARED_SELECTOR = YES;
321 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
322 | GCC_WARN_UNUSED_FUNCTION = YES;
323 | GCC_WARN_UNUSED_VARIABLE = YES;
324 | MACOSX_DEPLOYMENT_TARGET = 10.9;
325 | MTL_ENABLE_DEBUG_INFO = NO;
326 | ONLY_ACTIVE_ARCH = NO;
327 | SDKROOT = macosx;
328 | };
329 | name = Release;
330 | };
331 | C5AB32D61A8F9091002258B6 /* Debug */ = {
332 | isa = XCBuildConfiguration;
333 | buildSettings = {
334 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
335 | COMBINE_HIDPI_IMAGES = YES;
336 | CURRENT_PROJECT_VERSION = 8;
337 | INFOPLIST_FILE = AnyBar/Info.plist;
338 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks";
339 | MACOSX_DEPLOYMENT_TARGET = 10.9;
340 | MARKETING_VERSION = 0.2.3;
341 | PRODUCT_BUNDLE_IDENTIFIER = "tonsky.$(PRODUCT_NAME:rfc1034identifier)";
342 | PRODUCT_NAME = "$(TARGET_NAME)";
343 | };
344 | name = Debug;
345 | };
346 | C5AB32D71A8F9091002258B6 /* Release */ = {
347 | isa = XCBuildConfiguration;
348 | buildSettings = {
349 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
350 | COMBINE_HIDPI_IMAGES = YES;
351 | CURRENT_PROJECT_VERSION = 8;
352 | INFOPLIST_FILE = AnyBar/Info.plist;
353 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks";
354 | MACOSX_DEPLOYMENT_TARGET = 10.9;
355 | MARKETING_VERSION = 0.2.3;
356 | PRODUCT_BUNDLE_IDENTIFIER = "tonsky.$(PRODUCT_NAME:rfc1034identifier)";
357 | PRODUCT_NAME = "$(TARGET_NAME)";
358 | };
359 | name = Release;
360 | };
361 | /* End XCBuildConfiguration section */
362 |
363 | /* Begin XCConfigurationList section */
364 | C5AB32B31A8F9091002258B6 /* Build configuration list for PBXProject "AnyBar" */ = {
365 | isa = XCConfigurationList;
366 | buildConfigurations = (
367 | C5AB32D31A8F9091002258B6 /* Debug */,
368 | C5AB32D41A8F9091002258B6 /* Release */,
369 | );
370 | defaultConfigurationIsVisible = 0;
371 | defaultConfigurationName = Release;
372 | };
373 | C5AB32D51A8F9091002258B6 /* Build configuration list for PBXNativeTarget "AnyBar" */ = {
374 | isa = XCConfigurationList;
375 | buildConfigurations = (
376 | C5AB32D61A8F9091002258B6 /* Debug */,
377 | C5AB32D71A8F9091002258B6 /* Release */,
378 | );
379 | defaultConfigurationIsVisible = 0;
380 | defaultConfigurationName = Release;
381 | };
382 | /* End XCConfigurationList section */
383 | };
384 | rootObject = C5AB32B01A8F9091002258B6 /* Project object */;
385 | }
386 |
--------------------------------------------------------------------------------
/AnyBar/GCDAsyncUdpSocket.h:
--------------------------------------------------------------------------------
1 | //
2 | // GCDAsyncUdpSocket
3 | //
4 | // This class is in the public domain.
5 | // Originally created by Robbie Hanson of Deusty LLC.
6 | // Updated and maintained by Deusty LLC and the Apple development community.
7 | //
8 | // https://github.com/robbiehanson/CocoaAsyncSocket
9 | //
10 |
11 | #import
12 | #import
13 | #import
14 | #import
15 |
16 | extern NSString *const GCDAsyncUdpSocketException;
17 | extern NSString *const GCDAsyncUdpSocketErrorDomain;
18 |
19 | extern NSString *const GCDAsyncUdpSocketQueueName;
20 | extern NSString *const GCDAsyncUdpSocketThreadName;
21 |
22 | enum GCDAsyncUdpSocketError
23 | {
24 | GCDAsyncUdpSocketNoError = 0, // Never used
25 | GCDAsyncUdpSocketBadConfigError, // Invalid configuration
26 | GCDAsyncUdpSocketBadParamError, // Invalid parameter was passed
27 | GCDAsyncUdpSocketSendTimeoutError, // A send operation timed out
28 | GCDAsyncUdpSocketClosedError, // The socket was closed
29 | GCDAsyncUdpSocketOtherError, // Description provided in userInfo
30 | };
31 | typedef enum GCDAsyncUdpSocketError GCDAsyncUdpSocketError;
32 |
33 | /**
34 | * You may optionally set a receive filter for the socket.
35 | * A filter can provide several useful features:
36 | *
37 | * 1. Many times udp packets need to be parsed.
38 | * Since the filter can run in its own independent queue, you can parallelize this parsing quite easily.
39 | * The end result is a parallel socket io, datagram parsing, and packet processing.
40 | *
41 | * 2. Many times udp packets are discarded because they are duplicate/unneeded/unsolicited.
42 | * The filter can prevent such packets from arriving at the delegate.
43 | * And because the filter can run in its own independent queue, this doesn't slow down the delegate.
44 | *
45 | * - Since the udp protocol does not guarantee delivery, udp packets may be lost.
46 | * Many protocols built atop udp thus provide various resend/re-request algorithms.
47 | * This sometimes results in duplicate packets arriving.
48 | * A filter may allow you to architect the duplicate detection code to run in parallel to normal processing.
49 | *
50 | * - Since the udp socket may be connectionless, its possible for unsolicited packets to arrive.
51 | * Such packets need to be ignored.
52 | *
53 | * 3. Sometimes traffic shapers are needed to simulate real world environments.
54 | * A filter allows you to write custom code to simulate such environments.
55 | * The ability to code this yourself is especially helpful when your simulated environment
56 | * is more complicated than simple traffic shaping (e.g. simulating a cone port restricted router),
57 | * or the system tools to handle this aren't available (e.g. on a mobile device).
58 | *
59 | * @param data - The packet that was received.
60 | * @param address - The address the data was received from.
61 | * See utilities section for methods to extract info from address.
62 | * @param context - Out parameter you may optionally set, which will then be passed to the delegate method.
63 | * For example, filter block can parse the data and then,
64 | * pass the parsed data to the delegate.
65 | *
66 | * @returns - YES if the received packet should be passed onto the delegate.
67 | * NO if the received packet should be discarded, and not reported to the delegete.
68 | *
69 | * Example:
70 | *
71 | * GCDAsyncUdpSocketReceiveFilterBlock filter = ^BOOL (NSData *data, NSData *address, id *context) {
72 | *
73 | * MyProtocolMessage *msg = [MyProtocol parseMessage:data];
74 | *
75 | * *context = response;
76 | * return (response != nil);
77 | * };
78 | * [udpSocket setReceiveFilter:filter withQueue:myParsingQueue];
79 | *
80 | **/
81 | typedef BOOL (^GCDAsyncUdpSocketReceiveFilterBlock)(NSData *data, NSData *address, id *context);
82 |
83 | /**
84 | * You may optionally set a send filter for the socket.
85 | * A filter can provide several interesting possibilities:
86 | *
87 | * 1. Optional caching of resolved addresses for domain names.
88 | * The cache could later be consulted, resulting in fewer system calls to getaddrinfo.
89 | *
90 | * 2. Reusable modules of code for bandwidth monitoring.
91 | *
92 | * 3. Sometimes traffic shapers are needed to simulate real world environments.
93 | * A filter allows you to write custom code to simulate such environments.
94 | * The ability to code this yourself is especially helpful when your simulated environment
95 | * is more complicated than simple traffic shaping (e.g. simulating a cone port restricted router),
96 | * or the system tools to handle this aren't available (e.g. on a mobile device).
97 | *
98 | * @param data - The packet that was received.
99 | * @param address - The address the data was received from.
100 | * See utilities section for methods to extract info from address.
101 | * @param tag - The tag that was passed in the send method.
102 | *
103 | * @returns - YES if the packet should actually be sent over the socket.
104 | * NO if the packet should be silently dropped (not sent over the socket).
105 | *
106 | * Regardless of the return value, the delegate will be informed that the packet was successfully sent.
107 | *
108 | **/
109 | typedef BOOL (^GCDAsyncUdpSocketSendFilterBlock)(NSData *data, NSData *address, long tag);
110 |
111 |
112 | @interface GCDAsyncUdpSocket : NSObject
113 |
114 | /**
115 | * GCDAsyncUdpSocket uses the standard delegate paradigm,
116 | * but executes all delegate callbacks on a given delegate dispatch queue.
117 | * This allows for maximum concurrency, while at the same time providing easy thread safety.
118 | *
119 | * You MUST set a delegate AND delegate dispatch queue before attempting to
120 | * use the socket, or you will get an error.
121 | *
122 | * The socket queue is optional.
123 | * If you pass NULL, GCDAsyncSocket will automatically create its own socket queue.
124 | * If you choose to provide a socket queue, the socket queue must not be a concurrent queue,
125 | * then please see the discussion for the method markSocketQueueTargetQueue.
126 | *
127 | * The delegate queue and socket queue can optionally be the same.
128 | **/
129 | - (id)init;
130 | - (id)initWithSocketQueue:(dispatch_queue_t)sq;
131 | - (id)initWithDelegate:(id)aDelegate delegateQueue:(dispatch_queue_t)dq;
132 | - (id)initWithDelegate:(id)aDelegate delegateQueue:(dispatch_queue_t)dq socketQueue:(dispatch_queue_t)sq;
133 |
134 | #pragma mark Configuration
135 |
136 | - (id)delegate;
137 | - (void)setDelegate:(id)delegate;
138 | - (void)synchronouslySetDelegate:(id)delegate;
139 |
140 | - (dispatch_queue_t)delegateQueue;
141 | - (void)setDelegateQueue:(dispatch_queue_t)delegateQueue;
142 | - (void)synchronouslySetDelegateQueue:(dispatch_queue_t)delegateQueue;
143 |
144 | - (void)getDelegate:(id *)delegatePtr delegateQueue:(dispatch_queue_t *)delegateQueuePtr;
145 | - (void)setDelegate:(id)delegate delegateQueue:(dispatch_queue_t)delegateQueue;
146 | - (void)synchronouslySetDelegate:(id)delegate delegateQueue:(dispatch_queue_t)delegateQueue;
147 |
148 | /**
149 | * By default, both IPv4 and IPv6 are enabled.
150 | *
151 | * This means GCDAsyncUdpSocket automatically supports both protocols,
152 | * and can send to IPv4 or IPv6 addresses,
153 | * as well as receive over IPv4 and IPv6.
154 | *
155 | * For operations that require DNS resolution, GCDAsyncUdpSocket supports both IPv4 and IPv6.
156 | * If a DNS lookup returns only IPv4 results, GCDAsyncUdpSocket will automatically use IPv4.
157 | * If a DNS lookup returns only IPv6 results, GCDAsyncUdpSocket will automatically use IPv6.
158 | * If a DNS lookup returns both IPv4 and IPv6 results, then the protocol used depends on the configured preference.
159 | * If IPv4 is preferred, then IPv4 is used.
160 | * If IPv6 is preferred, then IPv6 is used.
161 | * If neutral, then the first IP version in the resolved array will be used.
162 | *
163 | * Starting with Mac OS X 10.7 Lion and iOS 5, the default IP preference is neutral.
164 | * On prior systems the default IP preference is IPv4.
165 | **/
166 | - (BOOL)isIPv4Enabled;
167 | - (void)setIPv4Enabled:(BOOL)flag;
168 |
169 | - (BOOL)isIPv6Enabled;
170 | - (void)setIPv6Enabled:(BOOL)flag;
171 |
172 | - (BOOL)isIPv4Preferred;
173 | - (BOOL)isIPv6Preferred;
174 | - (BOOL)isIPVersionNeutral;
175 |
176 | - (void)setPreferIPv4;
177 | - (void)setPreferIPv6;
178 | - (void)setIPVersionNeutral;
179 |
180 | /**
181 | * Gets/Sets the maximum size of the buffer that will be allocated for receive operations.
182 | * The default maximum size is 9216 bytes.
183 | *
184 | * The theoretical maximum size of any IPv4 UDP packet is UINT16_MAX = 65535.
185 | * The theoretical maximum size of any IPv6 UDP packet is UINT32_MAX = 4294967295.
186 | *
187 | * Since the OS/GCD notifies us of the size of each received UDP packet,
188 | * the actual allocated buffer size for each packet is exact.
189 | * And in practice the size of UDP packets is generally much smaller than the max.
190 | * Indeed most protocols will send and receive packets of only a few bytes,
191 | * or will set a limit on the size of packets to prevent fragmentation in the IP layer.
192 | *
193 | * If you set the buffer size too small, the sockets API in the OS will silently discard
194 | * any extra data, and you will not be notified of the error.
195 | **/
196 | - (uint16_t)maxReceiveIPv4BufferSize;
197 | - (void)setMaxReceiveIPv4BufferSize:(uint16_t)max;
198 |
199 | - (uint32_t)maxReceiveIPv6BufferSize;
200 | - (void)setMaxReceiveIPv6BufferSize:(uint32_t)max;
201 |
202 | /**
203 | * User data allows you to associate arbitrary information with the socket.
204 | * This data is not used internally in any way.
205 | **/
206 | - (id)userData;
207 | - (void)setUserData:(id)arbitraryUserData;
208 |
209 | #pragma mark Diagnostics
210 |
211 | /**
212 | * Returns the local address info for the socket.
213 | *
214 | * The localAddress method returns a sockaddr structure wrapped in a NSData object.
215 | * The localHost method returns the human readable IP address as a string.
216 | *
217 | * Note: Address info may not be available until after the socket has been binded, connected
218 | * or until after data has been sent.
219 | **/
220 | - (NSData *)localAddress;
221 | - (NSString *)localHost;
222 | - (uint16_t)localPort;
223 |
224 | - (NSData *)localAddress_IPv4;
225 | - (NSString *)localHost_IPv4;
226 | - (uint16_t)localPort_IPv4;
227 |
228 | - (NSData *)localAddress_IPv6;
229 | - (NSString *)localHost_IPv6;
230 | - (uint16_t)localPort_IPv6;
231 |
232 | /**
233 | * Returns the remote address info for the socket.
234 | *
235 | * The connectedAddress method returns a sockaddr structure wrapped in a NSData object.
236 | * The connectedHost method returns the human readable IP address as a string.
237 | *
238 | * Note: Since UDP is connectionless by design, connected address info
239 | * will not be available unless the socket is explicitly connected to a remote host/port.
240 | * If the socket is not connected, these methods will return nil / 0.
241 | **/
242 | - (NSData *)connectedAddress;
243 | - (NSString *)connectedHost;
244 | - (uint16_t)connectedPort;
245 |
246 | /**
247 | * Returns whether or not this socket has been connected to a single host.
248 | * By design, UDP is a connectionless protocol, and connecting is not needed.
249 | * If connected, the socket will only be able to send/receive data to/from the connected host.
250 | **/
251 | - (BOOL)isConnected;
252 |
253 | /**
254 | * Returns whether or not this socket has been closed.
255 | * The only way a socket can be closed is if you explicitly call one of the close methods.
256 | **/
257 | - (BOOL)isClosed;
258 |
259 | /**
260 | * Returns whether or not this socket is IPv4.
261 | *
262 | * By default this will be true, unless:
263 | * - IPv4 is disabled (via setIPv4Enabled:)
264 | * - The socket is explicitly bound to an IPv6 address
265 | * - The socket is connected to an IPv6 address
266 | **/
267 | - (BOOL)isIPv4;
268 |
269 | /**
270 | * Returns whether or not this socket is IPv6.
271 | *
272 | * By default this will be true, unless:
273 | * - IPv6 is disabled (via setIPv6Enabled:)
274 | * - The socket is explicitly bound to an IPv4 address
275 | * _ The socket is connected to an IPv4 address
276 | *
277 | * This method will also return false on platforms that do not support IPv6.
278 | * Note: The iPhone does not currently support IPv6.
279 | **/
280 | - (BOOL)isIPv6;
281 |
282 | #pragma mark Binding
283 |
284 | /**
285 | * Binds the UDP socket to the given port.
286 | * Binding should be done for server sockets that receive data prior to sending it.
287 | * Client sockets can skip binding,
288 | * as the OS will automatically assign the socket an available port when it starts sending data.
289 | *
290 | * You may optionally pass a port number of zero to immediately bind the socket,
291 | * yet still allow the OS to automatically assign an available port.
292 | *
293 | * You cannot bind a socket after its been connected.
294 | * You can only bind a socket once.
295 | * You can still connect a socket (if desired) after binding.
296 | *
297 | * On success, returns YES.
298 | * Otherwise returns NO, and sets errPtr. If you don't care about the error, you can pass NULL for errPtr.
299 | **/
300 | - (BOOL)bindToPort:(uint16_t)port error:(NSError **)errPtr;
301 |
302 | /**
303 | * Binds the UDP socket to the given port and optional interface.
304 | * Binding should be done for server sockets that receive data prior to sending it.
305 | * Client sockets can skip binding,
306 | * as the OS will automatically assign the socket an available port when it starts sending data.
307 | *
308 | * You may optionally pass a port number of zero to immediately bind the socket,
309 | * yet still allow the OS to automatically assign an available port.
310 | *
311 | * The interface may be a name (e.g. "en1" or "lo0") or the corresponding IP address (e.g. "192.168.4.35").
312 | * You may also use the special strings "localhost" or "loopback" to specify that
313 | * the socket only accept packets from the local machine.
314 | *
315 | * You cannot bind a socket after its been connected.
316 | * You can only bind a socket once.
317 | * You can still connect a socket (if desired) after binding.
318 | *
319 | * On success, returns YES.
320 | * Otherwise returns NO, and sets errPtr. If you don't care about the error, you can pass NULL for errPtr.
321 | **/
322 | - (BOOL)bindToPort:(uint16_t)port interface:(NSString *)interface error:(NSError **)errPtr;
323 |
324 | /**
325 | * Binds the UDP socket to the given address, specified as a sockaddr structure wrapped in a NSData object.
326 | *
327 | * If you have an existing struct sockaddr you can convert it to a NSData object like so:
328 | * struct sockaddr sa -> NSData *dsa = [NSData dataWithBytes:&remoteAddr length:remoteAddr.sa_len];
329 | * struct sockaddr *sa -> NSData *dsa = [NSData dataWithBytes:remoteAddr length:remoteAddr->sa_len];
330 | *
331 | * Binding should be done for server sockets that receive data prior to sending it.
332 | * Client sockets can skip binding,
333 | * as the OS will automatically assign the socket an available port when it starts sending data.
334 | *
335 | * You cannot bind a socket after its been connected.
336 | * You can only bind a socket once.
337 | * You can still connect a socket (if desired) after binding.
338 | *
339 | * On success, returns YES.
340 | * Otherwise returns NO, and sets errPtr. If you don't care about the error, you can pass NULL for errPtr.
341 | **/
342 | - (BOOL)bindToAddress:(NSData *)localAddr error:(NSError **)errPtr;
343 |
344 | #pragma mark Connecting
345 |
346 | /**
347 | * Connects the UDP socket to the given host and port.
348 | * By design, UDP is a connectionless protocol, and connecting is not needed.
349 | *
350 | * Choosing to connect to a specific host/port has the following effect:
351 | * - You will only be able to send data to the connected host/port.
352 | * - You will only be able to receive data from the connected host/port.
353 | * - You will receive ICMP messages that come from the connected host/port, such as "connection refused".
354 | *
355 | * The actual process of connecting a UDP socket does not result in any communication on the socket.
356 | * It simply changes the internal state of the socket.
357 | *
358 | * You cannot bind a socket after it has been connected.
359 | * You can only connect a socket once.
360 | *
361 | * The host may be a domain name (e.g. "deusty.com") or an IP address string (e.g. "192.168.0.2").
362 | *
363 | * This method is asynchronous as it requires a DNS lookup to resolve the given host name.
364 | * If an obvious error is detected, this method immediately returns NO and sets errPtr.
365 | * If you don't care about the error, you can pass nil for errPtr.
366 | * Otherwise, this method returns YES and begins the asynchronous connection process.
367 | * The result of the asynchronous connection process will be reported via the delegate methods.
368 | **/
369 | - (BOOL)connectToHost:(NSString *)host onPort:(uint16_t)port error:(NSError **)errPtr;
370 |
371 | /**
372 | * Connects the UDP socket to the given address, specified as a sockaddr structure wrapped in a NSData object.
373 | *
374 | * If you have an existing struct sockaddr you can convert it to a NSData object like so:
375 | * struct sockaddr sa -> NSData *dsa = [NSData dataWithBytes:&remoteAddr length:remoteAddr.sa_len];
376 | * struct sockaddr *sa -> NSData *dsa = [NSData dataWithBytes:remoteAddr length:remoteAddr->sa_len];
377 | *
378 | * By design, UDP is a connectionless protocol, and connecting is not needed.
379 | *
380 | * Choosing to connect to a specific address has the following effect:
381 | * - You will only be able to send data to the connected address.
382 | * - You will only be able to receive data from the connected address.
383 | * - You will receive ICMP messages that come from the connected address, such as "connection refused".
384 | *
385 | * Connecting a UDP socket does not result in any communication on the socket.
386 | * It simply changes the internal state of the socket.
387 | *
388 | * You cannot bind a socket after its been connected.
389 | * You can only connect a socket once.
390 | *
391 | * On success, returns YES.
392 | * Otherwise returns NO, and sets errPtr. If you don't care about the error, you can pass nil for errPtr.
393 | *
394 | * Note: Unlike the connectToHost:onPort:error: method, this method does not require a DNS lookup.
395 | * Thus when this method returns, the connection has either failed or fully completed.
396 | * In other words, this method is synchronous, unlike the asynchronous connectToHost::: method.
397 | * However, for compatibility and simplification of delegate code, if this method returns YES
398 | * then the corresponding delegate method (udpSocket:didConnectToHost:port:) is still invoked.
399 | **/
400 | - (BOOL)connectToAddress:(NSData *)remoteAddr error:(NSError **)errPtr;
401 |
402 | #pragma mark Multicast
403 |
404 | /**
405 | * Join multicast group.
406 | * Group should be an IP address (eg @"225.228.0.1").
407 | *
408 | * On success, returns YES.
409 | * Otherwise returns NO, and sets errPtr. If you don't care about the error, you can pass nil for errPtr.
410 | **/
411 | - (BOOL)joinMulticastGroup:(NSString *)group error:(NSError **)errPtr;
412 |
413 | /**
414 | * Join multicast group.
415 | * Group should be an IP address (eg @"225.228.0.1").
416 | * The interface may be a name (e.g. "en1" or "lo0") or the corresponding IP address (e.g. "192.168.4.35").
417 | *
418 | * On success, returns YES.
419 | * Otherwise returns NO, and sets errPtr. If you don't care about the error, you can pass nil for errPtr.
420 | **/
421 | - (BOOL)joinMulticastGroup:(NSString *)group onInterface:(NSString *)interface error:(NSError **)errPtr;
422 |
423 | - (BOOL)leaveMulticastGroup:(NSString *)group error:(NSError **)errPtr;
424 | - (BOOL)leaveMulticastGroup:(NSString *)group onInterface:(NSString *)interface error:(NSError **)errPtr;
425 |
426 | #pragma mark Broadcast
427 |
428 | /**
429 | * By default, the underlying socket in the OS will not allow you to send broadcast messages.
430 | * In order to send broadcast messages, you need to enable this functionality in the socket.
431 | *
432 | * A broadcast is a UDP message to addresses like "192.168.255.255" or "255.255.255.255" that is
433 | * delivered to every host on the network.
434 | * The reason this is generally disabled by default (by the OS) is to prevent
435 | * accidental broadcast messages from flooding the network.
436 | **/
437 | - (BOOL)enableBroadcast:(BOOL)flag error:(NSError **)errPtr;
438 |
439 | #pragma mark Sending
440 |
441 | /**
442 | * Asynchronously sends the given data, with the given timeout and tag.
443 | *
444 | * This method may only be used with a connected socket.
445 | * Recall that connecting is optional for a UDP socket.
446 | * For connected sockets, data can only be sent to the connected address.
447 | * For non-connected sockets, the remote destination is specified for each packet.
448 | * For more information about optionally connecting udp sockets, see the documentation for the connect methods above.
449 | *
450 | * @param data
451 | * The data to send.
452 | * If data is nil or zero-length, this method does nothing.
453 | * If passing NSMutableData, please read the thread-safety notice below.
454 | *
455 | * @param timeout
456 | * The timeout for the send opeartion.
457 | * If the timeout value is negative, the send operation will not use a timeout.
458 | *
459 | * @param tag
460 | * The tag is for your convenience.
461 | * It is not sent or received over the socket in any manner what-so-ever.
462 | * It is reported back as a parameter in the udpSocket:didSendDataWithTag:
463 | * or udpSocket:didNotSendDataWithTag:dueToError: methods.
464 | * You can use it as an array index, state id, type constant, etc.
465 | *
466 | *
467 | * Thread-Safety Note:
468 | * If the given data parameter is mutable (NSMutableData) then you MUST NOT alter the data while
469 | * the socket is sending it. In other words, it's not safe to alter the data until after the delegate method
470 | * udpSocket:didSendDataWithTag: or udpSocket:didNotSendDataWithTag:dueToError: is invoked signifying
471 | * that this particular send operation has completed.
472 | * This is due to the fact that GCDAsyncUdpSocket does NOT copy the data.
473 | * It simply retains it for performance reasons.
474 | * Often times, if NSMutableData is passed, it is because a request/response was built up in memory.
475 | * Copying this data adds an unwanted/unneeded overhead.
476 | * If you need to write data from an immutable buffer, and you need to alter the buffer before the socket
477 | * completes sending the bytes (which is NOT immediately after this method returns, but rather at a later time
478 | * when the delegate method notifies you), then you should first copy the bytes, and pass the copy to this method.
479 | **/
480 | - (void)sendData:(NSData *)data withTimeout:(NSTimeInterval)timeout tag:(long)tag;
481 |
482 | /**
483 | * Asynchronously sends the given data, with the given timeout and tag, to the given host and port.
484 | *
485 | * This method cannot be used with a connected socket.
486 | * Recall that connecting is optional for a UDP socket.
487 | * For connected sockets, data can only be sent to the connected address.
488 | * For non-connected sockets, the remote destination is specified for each packet.
489 | * For more information about optionally connecting udp sockets, see the documentation for the connect methods above.
490 | *
491 | * @param data
492 | * The data to send.
493 | * If data is nil or zero-length, this method does nothing.
494 | * If passing NSMutableData, please read the thread-safety notice below.
495 | *
496 | * @param host
497 | * The destination to send the udp packet to.
498 | * May be specified as a domain name (e.g. "deusty.com") or an IP address string (e.g. "192.168.0.2").
499 | * You may also use the convenience strings of "loopback" or "localhost".
500 | *
501 | * @param port
502 | * The port of the host to send to.
503 | *
504 | * @param timeout
505 | * The timeout for the send opeartion.
506 | * If the timeout value is negative, the send operation will not use a timeout.
507 | *
508 | * @param tag
509 | * The tag is for your convenience.
510 | * It is not sent or received over the socket in any manner what-so-ever.
511 | * It is reported back as a parameter in the udpSocket:didSendDataWithTag:
512 | * or udpSocket:didNotSendDataWithTag:dueToError: methods.
513 | * You can use it as an array index, state id, type constant, etc.
514 | *
515 | *
516 | * Thread-Safety Note:
517 | * If the given data parameter is mutable (NSMutableData) then you MUST NOT alter the data while
518 | * the socket is sending it. In other words, it's not safe to alter the data until after the delegate method
519 | * udpSocket:didSendDataWithTag: or udpSocket:didNotSendDataWithTag:dueToError: is invoked signifying
520 | * that this particular send operation has completed.
521 | * This is due to the fact that GCDAsyncUdpSocket does NOT copy the data.
522 | * It simply retains it for performance reasons.
523 | * Often times, if NSMutableData is passed, it is because a request/response was built up in memory.
524 | * Copying this data adds an unwanted/unneeded overhead.
525 | * If you need to write data from an immutable buffer, and you need to alter the buffer before the socket
526 | * completes sending the bytes (which is NOT immediately after this method returns, but rather at a later time
527 | * when the delegate method notifies you), then you should first copy the bytes, and pass the copy to this method.
528 | **/
529 | - (void)sendData:(NSData *)data
530 | toHost:(NSString *)host
531 | port:(uint16_t)port
532 | withTimeout:(NSTimeInterval)timeout
533 | tag:(long)tag;
534 |
535 | /**
536 | * Asynchronously sends the given data, with the given timeout and tag, to the given address.
537 | *
538 | * This method cannot be used with a connected socket.
539 | * Recall that connecting is optional for a UDP socket.
540 | * For connected sockets, data can only be sent to the connected address.
541 | * For non-connected sockets, the remote destination is specified for each packet.
542 | * For more information about optionally connecting udp sockets, see the documentation for the connect methods above.
543 | *
544 | * @param data
545 | * The data to send.
546 | * If data is nil or zero-length, this method does nothing.
547 | * If passing NSMutableData, please read the thread-safety notice below.
548 | *
549 | * @param remoteAddr
550 | * The address to send the data to (specified as a sockaddr structure wrapped in a NSData object).
551 | *
552 | * @param timeout
553 | * The timeout for the send opeartion.
554 | * If the timeout value is negative, the send operation will not use a timeout.
555 | *
556 | * @param tag
557 | * The tag is for your convenience.
558 | * It is not sent or received over the socket in any manner what-so-ever.
559 | * It is reported back as a parameter in the udpSocket:didSendDataWithTag:
560 | * or udpSocket:didNotSendDataWithTag:dueToError: methods.
561 | * You can use it as an array index, state id, type constant, etc.
562 | *
563 | *
564 | * Thread-Safety Note:
565 | * If the given data parameter is mutable (NSMutableData) then you MUST NOT alter the data while
566 | * the socket is sending it. In other words, it's not safe to alter the data until after the delegate method
567 | * udpSocket:didSendDataWithTag: or udpSocket:didNotSendDataWithTag:dueToError: is invoked signifying
568 | * that this particular send operation has completed.
569 | * This is due to the fact that GCDAsyncUdpSocket does NOT copy the data.
570 | * It simply retains it for performance reasons.
571 | * Often times, if NSMutableData is passed, it is because a request/response was built up in memory.
572 | * Copying this data adds an unwanted/unneeded overhead.
573 | * If you need to write data from an immutable buffer, and you need to alter the buffer before the socket
574 | * completes sending the bytes (which is NOT immediately after this method returns, but rather at a later time
575 | * when the delegate method notifies you), then you should first copy the bytes, and pass the copy to this method.
576 | **/
577 | - (void)sendData:(NSData *)data toAddress:(NSData *)remoteAddr withTimeout:(NSTimeInterval)timeout tag:(long)tag;
578 |
579 | /**
580 | * You may optionally set a send filter for the socket.
581 | * A filter can provide several interesting possibilities:
582 | *
583 | * 1. Optional caching of resolved addresses for domain names.
584 | * The cache could later be consulted, resulting in fewer system calls to getaddrinfo.
585 | *
586 | * 2. Reusable modules of code for bandwidth monitoring.
587 | *
588 | * 3. Sometimes traffic shapers are needed to simulate real world environments.
589 | * A filter allows you to write custom code to simulate such environments.
590 | * The ability to code this yourself is especially helpful when your simulated environment
591 | * is more complicated than simple traffic shaping (e.g. simulating a cone port restricted router),
592 | * or the system tools to handle this aren't available (e.g. on a mobile device).
593 | *
594 | * For more information about GCDAsyncUdpSocketSendFilterBlock, see the documentation for its typedef.
595 | * To remove a previously set filter, invoke this method and pass a nil filterBlock and NULL filterQueue.
596 | *
597 | * Note: This method invokes setSendFilter:withQueue:isAsynchronous: (documented below),
598 | * passing YES for the isAsynchronous parameter.
599 | **/
600 | - (void)setSendFilter:(GCDAsyncUdpSocketSendFilterBlock)filterBlock withQueue:(dispatch_queue_t)filterQueue;
601 |
602 | /**
603 | * The receive filter can be run via dispatch_async or dispatch_sync.
604 | * Most typical situations call for asynchronous operation.
605 | *
606 | * However, there are a few situations in which synchronous operation is preferred.
607 | * Such is the case when the filter is extremely minimal and fast.
608 | * This is because dispatch_sync is faster than dispatch_async.
609 | *
610 | * If you choose synchronous operation, be aware of possible deadlock conditions.
611 | * Since the socket queue is executing your block via dispatch_sync,
612 | * then you cannot perform any tasks which may invoke dispatch_sync on the socket queue.
613 | * For example, you can't query properties on the socket.
614 | **/
615 | - (void)setSendFilter:(GCDAsyncUdpSocketSendFilterBlock)filterBlock
616 | withQueue:(dispatch_queue_t)filterQueue
617 | isAsynchronous:(BOOL)isAsynchronous;
618 |
619 | #pragma mark Receiving
620 |
621 | /**
622 | * There are two modes of operation for receiving packets: one-at-a-time & continuous.
623 | *
624 | * In one-at-a-time mode, you call receiveOnce everytime your delegate is ready to process an incoming udp packet.
625 | * Receiving packets one-at-a-time may be better suited for implementing certain state machine code,
626 | * where your state machine may not always be ready to process incoming packets.
627 | *
628 | * In continuous mode, the delegate is invoked immediately everytime incoming udp packets are received.
629 | * Receiving packets continuously is better suited to real-time streaming applications.
630 | *
631 | * You may switch back and forth between one-at-a-time mode and continuous mode.
632 | * If the socket is currently in continuous mode, calling this method will switch it to one-at-a-time mode.
633 | *
634 | * When a packet is received (and not filtered by the optional receive filter),
635 | * the delegate method (udpSocket:didReceiveData:fromAddress:withFilterContext:) is invoked.
636 | *
637 | * If the socket is able to begin receiving packets, this method returns YES.
638 | * Otherwise it returns NO, and sets the errPtr with appropriate error information.
639 | *
640 | * An example error:
641 | * You created a udp socket to act as a server, and immediately called receive.
642 | * You forgot to first bind the socket to a port number, and received a error with a message like:
643 | * "Must bind socket before you can receive data."
644 | **/
645 | - (BOOL)receiveOnce:(NSError **)errPtr;
646 |
647 | /**
648 | * There are two modes of operation for receiving packets: one-at-a-time & continuous.
649 | *
650 | * In one-at-a-time mode, you call receiveOnce everytime your delegate is ready to process an incoming udp packet.
651 | * Receiving packets one-at-a-time may be better suited for implementing certain state machine code,
652 | * where your state machine may not always be ready to process incoming packets.
653 | *
654 | * In continuous mode, the delegate is invoked immediately everytime incoming udp packets are received.
655 | * Receiving packets continuously is better suited to real-time streaming applications.
656 | *
657 | * You may switch back and forth between one-at-a-time mode and continuous mode.
658 | * If the socket is currently in one-at-a-time mode, calling this method will switch it to continuous mode.
659 | *
660 | * For every received packet (not filtered by the optional receive filter),
661 | * the delegate method (udpSocket:didReceiveData:fromAddress:withFilterContext:) is invoked.
662 | *
663 | * If the socket is able to begin receiving packets, this method returns YES.
664 | * Otherwise it returns NO, and sets the errPtr with appropriate error information.
665 | *
666 | * An example error:
667 | * You created a udp socket to act as a server, and immediately called receive.
668 | * You forgot to first bind the socket to a port number, and received a error with a message like:
669 | * "Must bind socket before you can receive data."
670 | **/
671 | - (BOOL)beginReceiving:(NSError **)errPtr;
672 |
673 | /**
674 | * If the socket is currently receiving (beginReceiving has been called), this method pauses the receiving.
675 | * That is, it won't read any more packets from the underlying OS socket until beginReceiving is called again.
676 | *
677 | * Important Note:
678 | * GCDAsyncUdpSocket may be running in parallel with your code.
679 | * That is, your delegate is likely running on a separate thread/dispatch_queue.
680 | * When you invoke this method, GCDAsyncUdpSocket may have already dispatched delegate methods to be invoked.
681 | * Thus, if those delegate methods have already been dispatch_async'd,
682 | * your didReceive delegate method may still be invoked after this method has been called.
683 | * You should be aware of this, and program defensively.
684 | **/
685 | - (void)pauseReceiving;
686 |
687 | /**
688 | * You may optionally set a receive filter for the socket.
689 | * This receive filter may be set to run in its own queue (independent of delegate queue).
690 | *
691 | * A filter can provide several useful features.
692 | *
693 | * 1. Many times udp packets need to be parsed.
694 | * Since the filter can run in its own independent queue, you can parallelize this parsing quite easily.
695 | * The end result is a parallel socket io, datagram parsing, and packet processing.
696 | *
697 | * 2. Many times udp packets are discarded because they are duplicate/unneeded/unsolicited.
698 | * The filter can prevent such packets from arriving at the delegate.
699 | * And because the filter can run in its own independent queue, this doesn't slow down the delegate.
700 | *
701 | * - Since the udp protocol does not guarantee delivery, udp packets may be lost.
702 | * Many protocols built atop udp thus provide various resend/re-request algorithms.
703 | * This sometimes results in duplicate packets arriving.
704 | * A filter may allow you to architect the duplicate detection code to run in parallel to normal processing.
705 | *
706 | * - Since the udp socket may be connectionless, its possible for unsolicited packets to arrive.
707 | * Such packets need to be ignored.
708 | *
709 | * 3. Sometimes traffic shapers are needed to simulate real world environments.
710 | * A filter allows you to write custom code to simulate such environments.
711 | * The ability to code this yourself is especially helpful when your simulated environment
712 | * is more complicated than simple traffic shaping (e.g. simulating a cone port restricted router),
713 | * or the system tools to handle this aren't available (e.g. on a mobile device).
714 | *
715 | * Example:
716 | *
717 | * GCDAsyncUdpSocketReceiveFilterBlock filter = ^BOOL (NSData *data, NSData *address, id *context) {
718 | *
719 | * MyProtocolMessage *msg = [MyProtocol parseMessage:data];
720 | *
721 | * *context = response;
722 | * return (response != nil);
723 | * };
724 | * [udpSocket setReceiveFilter:filter withQueue:myParsingQueue];
725 | *
726 | * For more information about GCDAsyncUdpSocketReceiveFilterBlock, see the documentation for its typedef.
727 | * To remove a previously set filter, invoke this method and pass a nil filterBlock and NULL filterQueue.
728 | *
729 | * Note: This method invokes setReceiveFilter:withQueue:isAsynchronous: (documented below),
730 | * passing YES for the isAsynchronous parameter.
731 | **/
732 | - (void)setReceiveFilter:(GCDAsyncUdpSocketReceiveFilterBlock)filterBlock withQueue:(dispatch_queue_t)filterQueue;
733 |
734 | /**
735 | * The receive filter can be run via dispatch_async or dispatch_sync.
736 | * Most typical situations call for asynchronous operation.
737 | *
738 | * However, there are a few situations in which synchronous operation is preferred.
739 | * Such is the case when the filter is extremely minimal and fast.
740 | * This is because dispatch_sync is faster than dispatch_async.
741 | *
742 | * If you choose synchronous operation, be aware of possible deadlock conditions.
743 | * Since the socket queue is executing your block via dispatch_sync,
744 | * then you cannot perform any tasks which may invoke dispatch_sync on the socket queue.
745 | * For example, you can't query properties on the socket.
746 | **/
747 | - (void)setReceiveFilter:(GCDAsyncUdpSocketReceiveFilterBlock)filterBlock
748 | withQueue:(dispatch_queue_t)filterQueue
749 | isAsynchronous:(BOOL)isAsynchronous;
750 |
751 | #pragma mark Closing
752 |
753 | /**
754 | * Immediately closes the underlying socket.
755 | * Any pending send operations are discarded.
756 | *
757 | * The GCDAsyncUdpSocket instance may optionally be used again.
758 | * (it will setup/configure/use another unnderlying BSD socket).
759 | **/
760 | - (void)close;
761 |
762 | /**
763 | * Closes the underlying socket after all pending send operations have been sent.
764 | *
765 | * The GCDAsyncUdpSocket instance may optionally be used again.
766 | * (it will setup/configure/use another unnderlying BSD socket).
767 | **/
768 | - (void)closeAfterSending;
769 |
770 | #pragma mark Advanced
771 | /**
772 | * GCDAsyncSocket maintains thread safety by using an internal serial dispatch_queue.
773 | * In most cases, the instance creates this queue itself.
774 | * However, to allow for maximum flexibility, the internal queue may be passed in the init method.
775 | * This allows for some advanced options such as controlling socket priority via target queues.
776 | * However, when one begins to use target queues like this, they open the door to some specific deadlock issues.
777 | *
778 | * For example, imagine there are 2 queues:
779 | * dispatch_queue_t socketQueue;
780 | * dispatch_queue_t socketTargetQueue;
781 | *
782 | * If you do this (pseudo-code):
783 | * socketQueue.targetQueue = socketTargetQueue;
784 | *
785 | * Then all socketQueue operations will actually get run on the given socketTargetQueue.
786 | * This is fine and works great in most situations.
787 | * But if you run code directly from within the socketTargetQueue that accesses the socket,
788 | * you could potentially get deadlock. Imagine the following code:
789 | *
790 | * - (BOOL)socketHasSomething
791 | * {
792 | * __block BOOL result = NO;
793 | * dispatch_block_t block = ^{
794 | * result = [self someInternalMethodToBeRunOnlyOnSocketQueue];
795 | * }
796 | * if (is_executing_on_queue(socketQueue))
797 | * block();
798 | * else
799 | * dispatch_sync(socketQueue, block);
800 | *
801 | * return result;
802 | * }
803 | *
804 | * What happens if you call this method from the socketTargetQueue? The result is deadlock.
805 | * This is because the GCD API offers no mechanism to discover a queue's targetQueue.
806 | * Thus we have no idea if our socketQueue is configured with a targetQueue.
807 | * If we had this information, we could easily avoid deadlock.
808 | * But, since these API's are missing or unfeasible, you'll have to explicitly set it.
809 | *
810 | * IF you pass a socketQueue via the init method,
811 | * AND you've configured the passed socketQueue with a targetQueue,
812 | * THEN you should pass the end queue in the target hierarchy.
813 | *
814 | * For example, consider the following queue hierarchy:
815 | * socketQueue -> ipQueue -> moduleQueue
816 | *
817 | * This example demonstrates priority shaping within some server.
818 | * All incoming client connections from the same IP address are executed on the same target queue.
819 | * And all connections for a particular module are executed on the same target queue.
820 | * Thus, the priority of all networking for the entire module can be changed on the fly.
821 | * Additionally, networking traffic from a single IP cannot monopolize the module.
822 | *
823 | * Here's how you would accomplish something like that:
824 | * - (dispatch_queue_t)newSocketQueueForConnectionFromAddress:(NSData *)address onSocket:(GCDAsyncSocket *)sock
825 | * {
826 | * dispatch_queue_t socketQueue = dispatch_queue_create("", NULL);
827 | * dispatch_queue_t ipQueue = [self ipQueueForAddress:address];
828 | *
829 | * dispatch_set_target_queue(socketQueue, ipQueue);
830 | * dispatch_set_target_queue(iqQueue, moduleQueue);
831 | *
832 | * return socketQueue;
833 | * }
834 | * - (void)socket:(GCDAsyncSocket *)sock didAcceptNewSocket:(GCDAsyncSocket *)newSocket
835 | * {
836 | * [clientConnections addObject:newSocket];
837 | * [newSocket markSocketQueueTargetQueue:moduleQueue];
838 | * }
839 | *
840 | * Note: This workaround is ONLY needed if you intend to execute code directly on the ipQueue or moduleQueue.
841 | * This is often NOT the case, as such queues are used solely for execution shaping.
842 | **/
843 | - (void)markSocketQueueTargetQueue:(dispatch_queue_t)socketQueuesPreConfiguredTargetQueue;
844 | - (void)unmarkSocketQueueTargetQueue:(dispatch_queue_t)socketQueuesPreviouslyConfiguredTargetQueue;
845 |
846 | /**
847 | * It's not thread-safe to access certain variables from outside the socket's internal queue.
848 | *
849 | * For example, the socket file descriptor.
850 | * File descriptors are simply integers which reference an index in the per-process file table.
851 | * However, when one requests a new file descriptor (by opening a file or socket),
852 | * the file descriptor returned is guaranteed to be the lowest numbered unused descriptor.
853 | * So if we're not careful, the following could be possible:
854 | *
855 | * - Thread A invokes a method which returns the socket's file descriptor.
856 | * - The socket is closed via the socket's internal queue on thread B.
857 | * - Thread C opens a file, and subsequently receives the file descriptor that was previously the socket's FD.
858 | * - Thread A is now accessing/altering the file instead of the socket.
859 | *
860 | * In addition to this, other variables are not actually objects,
861 | * and thus cannot be retained/released or even autoreleased.
862 | * An example is the sslContext, of type SSLContextRef, which is actually a malloc'd struct.
863 | *
864 | * Although there are internal variables that make it difficult to maintain thread-safety,
865 | * it is important to provide access to these variables
866 | * to ensure this class can be used in a wide array of environments.
867 | * This method helps to accomplish this by invoking the current block on the socket's internal queue.
868 | * The methods below can be invoked from within the block to access
869 | * those generally thread-unsafe internal variables in a thread-safe manner.
870 | * The given block will be invoked synchronously on the socket's internal queue.
871 | *
872 | * If you save references to any protected variables and use them outside the block, you do so at your own peril.
873 | **/
874 | - (void)performBlock:(dispatch_block_t)block;
875 |
876 | /**
877 | * These methods are only available from within the context of a performBlock: invocation.
878 | * See the documentation for the performBlock: method above.
879 | *
880 | * Provides access to the socket's file descriptor(s).
881 | * If the socket isn't connected, or explicity bound to a particular interface,
882 | * it might actually have multiple internal socket file descriptors - one for IPv4 and one for IPv6.
883 | **/
884 | - (int)socketFD;
885 | - (int)socket4FD;
886 | - (int)socket6FD;
887 |
888 | #if TARGET_OS_IPHONE
889 |
890 | /**
891 | * These methods are only available from within the context of a performBlock: invocation.
892 | * See the documentation for the performBlock: method above.
893 | *
894 | * Returns (creating if necessary) a CFReadStream/CFWriteStream for the internal socket.
895 | *
896 | * Generally GCDAsyncUdpSocket doesn't use CFStream. (It uses the faster GCD API's.)
897 | * However, if you need one for any reason,
898 | * these methods are a convenient way to get access to a safe instance of one.
899 | **/
900 | - (CFReadStreamRef)readStream;
901 | - (CFWriteStreamRef)writeStream;
902 |
903 | /**
904 | * This method is only available from within the context of a performBlock: invocation.
905 | * See the documentation for the performBlock: method above.
906 | *
907 | * Configures the socket to allow it to operate when the iOS application has been backgrounded.
908 | * In other words, this method creates a read & write stream, and invokes:
909 | *
910 | * CFReadStreamSetProperty(readStream, kCFStreamNetworkServiceType, kCFStreamNetworkServiceTypeVoIP);
911 | * CFWriteStreamSetProperty(writeStream, kCFStreamNetworkServiceType, kCFStreamNetworkServiceTypeVoIP);
912 | *
913 | * Returns YES if successful, NO otherwise.
914 | *
915 | * Example usage:
916 | *
917 | * [asyncUdpSocket performBlock:^{
918 | * [asyncUdpSocket enableBackgroundingOnSocket];
919 | * }];
920 | *
921 | *
922 | * NOTE : Apple doesn't currently support backgrounding UDP sockets. (Only TCP for now).
923 | **/
924 | //- (BOOL)enableBackgroundingOnSockets;
925 |
926 | #endif
927 |
928 | #pragma mark Utilities
929 |
930 | /**
931 | * Extracting host/port/family information from raw address data.
932 | **/
933 |
934 | + (NSString *)hostFromAddress:(NSData *)address;
935 | + (uint16_t)portFromAddress:(NSData *)address;
936 | + (int)familyFromAddress:(NSData *)address;
937 |
938 | + (BOOL)isIPv4Address:(NSData *)address;
939 | + (BOOL)isIPv6Address:(NSData *)address;
940 |
941 | + (BOOL)getHost:(NSString **)hostPtr port:(uint16_t *)portPtr fromAddress:(NSData *)address;
942 | + (BOOL)getHost:(NSString **)hostPtr port:(uint16_t *)portPtr family:(int *)afPtr fromAddress:(NSData *)address;
943 |
944 | @end
945 |
946 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
947 | #pragma mark -
948 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
949 |
950 | @protocol GCDAsyncUdpSocketDelegate
951 | @optional
952 |
953 | /**
954 | * By design, UDP is a connectionless protocol, and connecting is not needed.
955 | * However, you may optionally choose to connect to a particular host for reasons
956 | * outlined in the documentation for the various connect methods listed above.
957 | *
958 | * This method is called if one of the connect methods are invoked, and the connection is successful.
959 | **/
960 | - (void)udpSocket:(GCDAsyncUdpSocket *)sock didConnectToAddress:(NSData *)address;
961 |
962 | /**
963 | * By design, UDP is a connectionless protocol, and connecting is not needed.
964 | * However, you may optionally choose to connect to a particular host for reasons
965 | * outlined in the documentation for the various connect methods listed above.
966 | *
967 | * This method is called if one of the connect methods are invoked, and the connection fails.
968 | * This may happen, for example, if a domain name is given for the host and the domain name is unable to be resolved.
969 | **/
970 | - (void)udpSocket:(GCDAsyncUdpSocket *)sock didNotConnect:(NSError *)error;
971 |
972 | /**
973 | * Called when the datagram with the given tag has been sent.
974 | **/
975 | - (void)udpSocket:(GCDAsyncUdpSocket *)sock didSendDataWithTag:(long)tag;
976 |
977 | /**
978 | * Called if an error occurs while trying to send a datagram.
979 | * This could be due to a timeout, or something more serious such as the data being too large to fit in a sigle packet.
980 | **/
981 | - (void)udpSocket:(GCDAsyncUdpSocket *)sock didNotSendDataWithTag:(long)tag dueToError:(NSError *)error;
982 |
983 | /**
984 | * Called when the socket has received the requested datagram.
985 | **/
986 | - (void)udpSocket:(GCDAsyncUdpSocket *)sock didReceiveData:(NSData *)data
987 | fromAddress:(NSData *)address
988 | withFilterContext:(id)filterContext;
989 |
990 | /**
991 | * Called when the socket is closed.
992 | **/
993 | - (void)udpSocketDidClose:(GCDAsyncUdpSocket *)sock withError:(NSError *)error;
994 |
995 | @end
996 |
997 |
--------------------------------------------------------------------------------
/AnyBar/GCDAsyncSocket.h:
--------------------------------------------------------------------------------
1 | //
2 | // GCDAsyncSocket.h
3 | //
4 | // This class is in the public domain.
5 | // Originally created by Robbie Hanson in Q3 2010.
6 | // Updated and maintained by Deusty LLC and the Apple development community.
7 | //
8 | // https://github.com/robbiehanson/CocoaAsyncSocket
9 | //
10 |
11 | #import
12 | #import
13 | #import
14 | #import
15 | #import
16 |
17 | #include // AF_INET, AF_INET6
18 |
19 | @class GCDAsyncReadPacket;
20 | @class GCDAsyncWritePacket;
21 | @class GCDAsyncSocketPreBuffer;
22 |
23 | extern NSString *const GCDAsyncSocketException;
24 | extern NSString *const GCDAsyncSocketErrorDomain;
25 |
26 | extern NSString *const GCDAsyncSocketQueueName;
27 | extern NSString *const GCDAsyncSocketThreadName;
28 |
29 | extern NSString *const GCDAsyncSocketManuallyEvaluateTrust;
30 | #if TARGET_OS_IPHONE
31 | extern NSString *const GCDAsyncSocketUseCFStreamForTLS;
32 | #endif
33 | #define GCDAsyncSocketSSLPeerName (NSString *)kCFStreamSSLPeerName
34 | #define GCDAsyncSocketSSLCertificates (NSString *)kCFStreamSSLCertificates
35 | #define GCDAsyncSocketSSLIsServer (NSString *)kCFStreamSSLIsServer
36 | extern NSString *const GCDAsyncSocketSSLPeerID;
37 | extern NSString *const GCDAsyncSocketSSLProtocolVersionMin;
38 | extern NSString *const GCDAsyncSocketSSLProtocolVersionMax;
39 | extern NSString *const GCDAsyncSocketSSLSessionOptionFalseStart;
40 | extern NSString *const GCDAsyncSocketSSLSessionOptionSendOneByteRecord;
41 | extern NSString *const GCDAsyncSocketSSLCipherSuites;
42 | #if !TARGET_OS_IPHONE
43 | extern NSString *const GCDAsyncSocketSSLDiffieHellmanParameters;
44 | #endif
45 |
46 | #define GCDAsyncSocketLoggingContext 65535
47 |
48 |
49 | enum GCDAsyncSocketError
50 | {
51 | GCDAsyncSocketNoError = 0, // Never used
52 | GCDAsyncSocketBadConfigError, // Invalid configuration
53 | GCDAsyncSocketBadParamError, // Invalid parameter was passed
54 | GCDAsyncSocketConnectTimeoutError, // A connect operation timed out
55 | GCDAsyncSocketReadTimeoutError, // A read operation timed out
56 | GCDAsyncSocketWriteTimeoutError, // A write operation timed out
57 | GCDAsyncSocketReadMaxedOutError, // Reached set maxLength without completing
58 | GCDAsyncSocketClosedError, // The remote peer closed the connection
59 | GCDAsyncSocketOtherError, // Description provided in userInfo
60 | };
61 | typedef enum GCDAsyncSocketError GCDAsyncSocketError;
62 |
63 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
64 | #pragma mark -
65 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
66 |
67 | @interface GCDAsyncSocket : NSObject
68 |
69 | /**
70 | * GCDAsyncSocket uses the standard delegate paradigm,
71 | * but executes all delegate callbacks on a given delegate dispatch queue.
72 | * This allows for maximum concurrency, while at the same time providing easy thread safety.
73 | *
74 | * You MUST set a delegate AND delegate dispatch queue before attempting to
75 | * use the socket, or you will get an error.
76 | *
77 | * The socket queue is optional.
78 | * If you pass NULL, GCDAsyncSocket will automatically create it's own socket queue.
79 | * If you choose to provide a socket queue, the socket queue must not be a concurrent queue.
80 | * If you choose to provide a socket queue, and the socket queue has a configured target queue,
81 | * then please see the discussion for the method markSocketQueueTargetQueue.
82 | *
83 | * The delegate queue and socket queue can optionally be the same.
84 | **/
85 | - (id)init;
86 | - (id)initWithSocketQueue:(dispatch_queue_t)sq;
87 | - (id)initWithDelegate:(id)aDelegate delegateQueue:(dispatch_queue_t)dq;
88 | - (id)initWithDelegate:(id)aDelegate delegateQueue:(dispatch_queue_t)dq socketQueue:(dispatch_queue_t)sq;
89 |
90 | #pragma mark Configuration
91 |
92 | @property (atomic, weak, readwrite) id delegate;
93 | #if OS_OBJECT_USE_OBJC
94 | @property (atomic, strong, readwrite) dispatch_queue_t delegateQueue;
95 | #else
96 | @property (atomic, assign, readwrite) dispatch_queue_t delegateQueue;
97 | #endif
98 |
99 | - (void)getDelegate:(id *)delegatePtr delegateQueue:(dispatch_queue_t *)delegateQueuePtr;
100 | - (void)setDelegate:(id)delegate delegateQueue:(dispatch_queue_t)delegateQueue;
101 |
102 | /**
103 | * If you are setting the delegate to nil within the delegate's dealloc method,
104 | * you may need to use the synchronous versions below.
105 | **/
106 | - (void)synchronouslySetDelegate:(id)delegate;
107 | - (void)synchronouslySetDelegateQueue:(dispatch_queue_t)delegateQueue;
108 | - (void)synchronouslySetDelegate:(id)delegate delegateQueue:(dispatch_queue_t)delegateQueue;
109 |
110 | /**
111 | * By default, both IPv4 and IPv6 are enabled.
112 | *
113 | * For accepting incoming connections, this means GCDAsyncSocket automatically supports both protocols,
114 | * and can simulataneously accept incoming connections on either protocol.
115 | *
116 | * For outgoing connections, this means GCDAsyncSocket can connect to remote hosts running either protocol.
117 | * If a DNS lookup returns only IPv4 results, GCDAsyncSocket will automatically use IPv4.
118 | * If a DNS lookup returns only IPv6 results, GCDAsyncSocket will automatically use IPv6.
119 | * If a DNS lookup returns both IPv4 and IPv6 results, the preferred protocol will be chosen.
120 | * By default, the preferred protocol is IPv4, but may be configured as desired.
121 | **/
122 |
123 | @property (atomic, assign, readwrite, getter=isIPv4Enabled) BOOL IPv4Enabled;
124 | @property (atomic, assign, readwrite, getter=isIPv6Enabled) BOOL IPv6Enabled;
125 |
126 | @property (atomic, assign, readwrite, getter=isIPv4PreferredOverIPv6) BOOL IPv4PreferredOverIPv6;
127 |
128 | /**
129 | * User data allows you to associate arbitrary information with the socket.
130 | * This data is not used internally by socket in any way.
131 | **/
132 | @property (atomic, strong, readwrite) id userData;
133 |
134 | #pragma mark Accepting
135 |
136 | /**
137 | * Tells the socket to begin listening and accepting connections on the given port.
138 | * When a connection is accepted, a new instance of GCDAsyncSocket will be spawned to handle it,
139 | * and the socket:didAcceptNewSocket: delegate method will be invoked.
140 | *
141 | * The socket will listen on all available interfaces (e.g. wifi, ethernet, etc)
142 | **/
143 | - (BOOL)acceptOnPort:(uint16_t)port error:(NSError **)errPtr;
144 |
145 | /**
146 | * This method is the same as acceptOnPort:error: with the
147 | * additional option of specifying which interface to listen on.
148 | *
149 | * For example, you could specify that the socket should only accept connections over ethernet,
150 | * and not other interfaces such as wifi.
151 | *
152 | * The interface may be specified by name (e.g. "en1" or "lo0") or by IP address (e.g. "192.168.4.34").
153 | * You may also use the special strings "localhost" or "loopback" to specify that
154 | * the socket only accept connections from the local machine.
155 | *
156 | * You can see the list of interfaces via the command line utility "ifconfig",
157 | * or programmatically via the getifaddrs() function.
158 | *
159 | * To accept connections on any interface pass nil, or simply use the acceptOnPort:error: method.
160 | **/
161 | - (BOOL)acceptOnInterface:(NSString *)interface port:(uint16_t)port error:(NSError **)errPtr;
162 |
163 | #pragma mark Connecting
164 |
165 | /**
166 | * Connects to the given host and port.
167 | *
168 | * This method invokes connectToHost:onPort:viaInterface:withTimeout:error:
169 | * and uses the default interface, and no timeout.
170 | **/
171 | - (BOOL)connectToHost:(NSString *)host onPort:(uint16_t)port error:(NSError **)errPtr;
172 |
173 | /**
174 | * Connects to the given host and port with an optional timeout.
175 | *
176 | * This method invokes connectToHost:onPort:viaInterface:withTimeout:error: and uses the default interface.
177 | **/
178 | - (BOOL)connectToHost:(NSString *)host
179 | onPort:(uint16_t)port
180 | withTimeout:(NSTimeInterval)timeout
181 | error:(NSError **)errPtr;
182 |
183 | /**
184 | * Connects to the given host & port, via the optional interface, with an optional timeout.
185 | *
186 | * The host may be a domain name (e.g. "deusty.com") or an IP address string (e.g. "192.168.0.2").
187 | * The host may also be the special strings "localhost" or "loopback" to specify connecting
188 | * to a service on the local machine.
189 | *
190 | * The interface may be a name (e.g. "en1" or "lo0") or the corresponding IP address (e.g. "192.168.4.35").
191 | * The interface may also be used to specify the local port (see below).
192 | *
193 | * To not time out use a negative time interval.
194 | *
195 | * This method will return NO if an error is detected, and set the error pointer (if one was given).
196 | * Possible errors would be a nil host, invalid interface, or socket is already connected.
197 | *
198 | * If no errors are detected, this method will start a background connect operation and immediately return YES.
199 | * The delegate callbacks are used to notify you when the socket connects, or if the host was unreachable.
200 | *
201 | * Since this class supports queued reads and writes, you can immediately start reading and/or writing.
202 | * All read/write operations will be queued, and upon socket connection,
203 | * the operations will be dequeued and processed in order.
204 | *
205 | * The interface may optionally contain a port number at the end of the string, separated by a colon.
206 | * This allows you to specify the local port that should be used for the outgoing connection. (read paragraph to end)
207 | * To specify both interface and local port: "en1:8082" or "192.168.4.35:2424".
208 | * To specify only local port: ":8082".
209 | * Please note this is an advanced feature, and is somewhat hidden on purpose.
210 | * You should understand that 99.999% of the time you should NOT specify the local port for an outgoing connection.
211 | * If you think you need to, there is a very good chance you have a fundamental misunderstanding somewhere.
212 | * Local ports do NOT need to match remote ports. In fact, they almost never do.
213 | * This feature is here for networking professionals using very advanced techniques.
214 | **/
215 | - (BOOL)connectToHost:(NSString *)host
216 | onPort:(uint16_t)port
217 | viaInterface:(NSString *)interface
218 | withTimeout:(NSTimeInterval)timeout
219 | error:(NSError **)errPtr;
220 |
221 | /**
222 | * Connects to the given address, specified as a sockaddr structure wrapped in a NSData object.
223 | * For example, a NSData object returned from NSNetService's addresses method.
224 | *
225 | * If you have an existing struct sockaddr you can convert it to a NSData object like so:
226 | * struct sockaddr sa -> NSData *dsa = [NSData dataWithBytes:&remoteAddr length:remoteAddr.sa_len];
227 | * struct sockaddr *sa -> NSData *dsa = [NSData dataWithBytes:remoteAddr length:remoteAddr->sa_len];
228 | *
229 | * This method invokes connectToAdd
230 | **/
231 | - (BOOL)connectToAddress:(NSData *)remoteAddr error:(NSError **)errPtr;
232 |
233 | /**
234 | * This method is the same as connectToAddress:error: with an additional timeout option.
235 | * To not time out use a negative time interval, or simply use the connectToAddress:error: method.
236 | **/
237 | - (BOOL)connectToAddress:(NSData *)remoteAddr withTimeout:(NSTimeInterval)timeout error:(NSError **)errPtr;
238 |
239 | /**
240 | * Connects to the given address, using the specified interface and timeout.
241 | *
242 | * The address is specified as a sockaddr structure wrapped in a NSData object.
243 | * For example, a NSData object returned from NSNetService's addresses method.
244 | *
245 | * If you have an existing struct sockaddr you can convert it to a NSData object like so:
246 | * struct sockaddr sa -> NSData *dsa = [NSData dataWithBytes:&remoteAddr length:remoteAddr.sa_len];
247 | * struct sockaddr *sa -> NSData *dsa = [NSData dataWithBytes:remoteAddr length:remoteAddr->sa_len];
248 | *
249 | * The interface may be a name (e.g. "en1" or "lo0") or the corresponding IP address (e.g. "192.168.4.35").
250 | * The interface may also be used to specify the local port (see below).
251 | *
252 | * The timeout is optional. To not time out use a negative time interval.
253 | *
254 | * This method will return NO if an error is detected, and set the error pointer (if one was given).
255 | * Possible errors would be a nil host, invalid interface, or socket is already connected.
256 | *
257 | * If no errors are detected, this method will start a background connect operation and immediately return YES.
258 | * The delegate callbacks are used to notify you when the socket connects, or if the host was unreachable.
259 | *
260 | * Since this class supports queued reads and writes, you can immediately start reading and/or writing.
261 | * All read/write operations will be queued, and upon socket connection,
262 | * the operations will be dequeued and processed in order.
263 | *
264 | * The interface may optionally contain a port number at the end of the string, separated by a colon.
265 | * This allows you to specify the local port that should be used for the outgoing connection. (read paragraph to end)
266 | * To specify both interface and local port: "en1:8082" or "192.168.4.35:2424".
267 | * To specify only local port: ":8082".
268 | * Please note this is an advanced feature, and is somewhat hidden on purpose.
269 | * You should understand that 99.999% of the time you should NOT specify the local port for an outgoing connection.
270 | * If you think you need to, there is a very good chance you have a fundamental misunderstanding somewhere.
271 | * Local ports do NOT need to match remote ports. In fact, they almost never do.
272 | * This feature is here for networking professionals using very advanced techniques.
273 | **/
274 | - (BOOL)connectToAddress:(NSData *)remoteAddr
275 | viaInterface:(NSString *)interface
276 | withTimeout:(NSTimeInterval)timeout
277 | error:(NSError **)errPtr;
278 |
279 | #pragma mark Disconnecting
280 |
281 | /**
282 | * Disconnects immediately (synchronously). Any pending reads or writes are dropped.
283 | *
284 | * If the socket is not already disconnected, an invocation to the socketDidDisconnect:withError: delegate method
285 | * will be queued onto the delegateQueue asynchronously (behind any previously queued delegate methods).
286 | * In other words, the disconnected delegate method will be invoked sometime shortly after this method returns.
287 | *
288 | * Please note the recommended way of releasing a GCDAsyncSocket instance (e.g. in a dealloc method)
289 | * [asyncSocket setDelegate:nil];
290 | * [asyncSocket disconnect];
291 | * [asyncSocket release];
292 | *
293 | * If you plan on disconnecting the socket, and then immediately asking it to connect again,
294 | * you'll likely want to do so like this:
295 | * [asyncSocket setDelegate:nil];
296 | * [asyncSocket disconnect];
297 | * [asyncSocket setDelegate:self];
298 | * [asyncSocket connect...];
299 | **/
300 | - (void)disconnect;
301 |
302 | /**
303 | * Disconnects after all pending reads have completed.
304 | * After calling this, the read and write methods will do nothing.
305 | * The socket will disconnect even if there are still pending writes.
306 | **/
307 | - (void)disconnectAfterReading;
308 |
309 | /**
310 | * Disconnects after all pending writes have completed.
311 | * After calling this, the read and write methods will do nothing.
312 | * The socket will disconnect even if there are still pending reads.
313 | **/
314 | - (void)disconnectAfterWriting;
315 |
316 | /**
317 | * Disconnects after all pending reads and writes have completed.
318 | * After calling this, the read and write methods will do nothing.
319 | **/
320 | - (void)disconnectAfterReadingAndWriting;
321 |
322 | #pragma mark Diagnostics
323 |
324 | /**
325 | * Returns whether the socket is disconnected or connected.
326 | *
327 | * A disconnected socket may be recycled.
328 | * That is, it can used again for connecting or listening.
329 | *
330 | * If a socket is in the process of connecting, it may be neither disconnected nor connected.
331 | **/
332 | @property (atomic, readonly) BOOL isDisconnected;
333 | @property (atomic, readonly) BOOL isConnected;
334 |
335 | /**
336 | * Returns the local or remote host and port to which this socket is connected, or nil and 0 if not connected.
337 | * The host will be an IP address.
338 | **/
339 | @property (atomic, readonly) NSString *connectedHost;
340 | @property (atomic, readonly) uint16_t connectedPort;
341 |
342 | @property (atomic, readonly) NSString *localHost;
343 | @property (atomic, readonly) uint16_t localPort;
344 |
345 | /**
346 | * Returns the local or remote address to which this socket is connected,
347 | * specified as a sockaddr structure wrapped in a NSData object.
348 | *
349 | * @seealso connectedHost
350 | * @seealso connectedPort
351 | * @seealso localHost
352 | * @seealso localPort
353 | **/
354 | @property (atomic, readonly) NSData *connectedAddress;
355 | @property (atomic, readonly) NSData *localAddress;
356 |
357 | /**
358 | * Returns whether the socket is IPv4 or IPv6.
359 | * An accepting socket may be both.
360 | **/
361 | @property (atomic, readonly) BOOL isIPv4;
362 | @property (atomic, readonly) BOOL isIPv6;
363 |
364 | /**
365 | * Returns whether or not the socket has been secured via SSL/TLS.
366 | *
367 | * See also the startTLS method.
368 | **/
369 | @property (atomic, readonly) BOOL isSecure;
370 |
371 | #pragma mark Reading
372 |
373 | // The readData and writeData methods won't block (they are asynchronous).
374 | //
375 | // When a read is complete the socket:didReadData:withTag: delegate method is dispatched on the delegateQueue.
376 | // When a write is complete the socket:didWriteDataWithTag: delegate method is dispatched on the delegateQueue.
377 | //
378 | // You may optionally set a timeout for any read/write operation. (To not timeout, use a negative time interval.)
379 | // If a read/write opertion times out, the corresponding "socket:shouldTimeout..." delegate method
380 | // is called to optionally allow you to extend the timeout.
381 | // Upon a timeout, the "socket:didDisconnectWithError:" method is called
382 | //
383 | // The tag is for your convenience.
384 | // You can use it as an array index, step number, state id, pointer, etc.
385 |
386 | /**
387 | * Reads the first available bytes that become available on the socket.
388 | *
389 | * If the timeout value is negative, the read operation will not use a timeout.
390 | **/
391 | - (void)readDataWithTimeout:(NSTimeInterval)timeout tag:(long)tag;
392 |
393 | /**
394 | * Reads the first available bytes that become available on the socket.
395 | * The bytes will be appended to the given byte buffer starting at the given offset.
396 | * The given buffer will automatically be increased in size if needed.
397 | *
398 | * If the timeout value is negative, the read operation will not use a timeout.
399 | * If the buffer if nil, the socket will create a buffer for you.
400 | *
401 | * If the bufferOffset is greater than the length of the given buffer,
402 | * the method will do nothing, and the delegate will not be called.
403 | *
404 | * If you pass a buffer, you must not alter it in any way while the socket is using it.
405 | * After completion, the data returned in socket:didReadData:withTag: will be a subset of the given buffer.
406 | * That is, it will reference the bytes that were appended to the given buffer via
407 | * the method [NSData dataWithBytesNoCopy:length:freeWhenDone:NO].
408 | **/
409 | - (void)readDataWithTimeout:(NSTimeInterval)timeout
410 | buffer:(NSMutableData *)buffer
411 | bufferOffset:(NSUInteger)offset
412 | tag:(long)tag;
413 |
414 | /**
415 | * Reads the first available bytes that become available on the socket.
416 | * The bytes will be appended to the given byte buffer starting at the given offset.
417 | * The given buffer will automatically be increased in size if needed.
418 | * A maximum of length bytes will be read.
419 | *
420 | * If the timeout value is negative, the read operation will not use a timeout.
421 | * If the buffer if nil, a buffer will automatically be created for you.
422 | * If maxLength is zero, no length restriction is enforced.
423 | *
424 | * If the bufferOffset is greater than the length of the given buffer,
425 | * the method will do nothing, and the delegate will not be called.
426 | *
427 | * If you pass a buffer, you must not alter it in any way while the socket is using it.
428 | * After completion, the data returned in socket:didReadData:withTag: will be a subset of the given buffer.
429 | * That is, it will reference the bytes that were appended to the given buffer via
430 | * the method [NSData dataWithBytesNoCopy:length:freeWhenDone:NO].
431 | **/
432 | - (void)readDataWithTimeout:(NSTimeInterval)timeout
433 | buffer:(NSMutableData *)buffer
434 | bufferOffset:(NSUInteger)offset
435 | maxLength:(NSUInteger)length
436 | tag:(long)tag;
437 |
438 | /**
439 | * Reads the given number of bytes.
440 | *
441 | * If the timeout value is negative, the read operation will not use a timeout.
442 | *
443 | * If the length is 0, this method does nothing and the delegate is not called.
444 | **/
445 | - (void)readDataToLength:(NSUInteger)length withTimeout:(NSTimeInterval)timeout tag:(long)tag;
446 |
447 | /**
448 | * Reads the given number of bytes.
449 | * The bytes will be appended to the given byte buffer starting at the given offset.
450 | * The given buffer will automatically be increased in size if needed.
451 | *
452 | * If the timeout value is negative, the read operation will not use a timeout.
453 | * If the buffer if nil, a buffer will automatically be created for you.
454 | *
455 | * If the length is 0, this method does nothing and the delegate is not called.
456 | * If the bufferOffset is greater than the length of the given buffer,
457 | * the method will do nothing, and the delegate will not be called.
458 | *
459 | * If you pass a buffer, you must not alter it in any way while AsyncSocket is using it.
460 | * After completion, the data returned in socket:didReadData:withTag: will be a subset of the given buffer.
461 | * That is, it will reference the bytes that were appended to the given buffer via
462 | * the method [NSData dataWithBytesNoCopy:length:freeWhenDone:NO].
463 | **/
464 | - (void)readDataToLength:(NSUInteger)length
465 | withTimeout:(NSTimeInterval)timeout
466 | buffer:(NSMutableData *)buffer
467 | bufferOffset:(NSUInteger)offset
468 | tag:(long)tag;
469 |
470 | /**
471 | * Reads bytes until (and including) the passed "data" parameter, which acts as a separator.
472 | *
473 | * If the timeout value is negative, the read operation will not use a timeout.
474 | *
475 | * If you pass nil or zero-length data as the "data" parameter,
476 | * the method will do nothing (except maybe print a warning), and the delegate will not be called.
477 | *
478 | * To read a line from the socket, use the line separator (e.g. CRLF for HTTP, see below) as the "data" parameter.
479 | * If you're developing your own custom protocol, be sure your separator can not occur naturally as
480 | * part of the data between separators.
481 | * For example, imagine you want to send several small documents over a socket.
482 | * Using CRLF as a separator is likely unwise, as a CRLF could easily exist within the documents.
483 | * In this particular example, it would be better to use a protocol similar to HTTP with
484 | * a header that includes the length of the document.
485 | * Also be careful that your separator cannot occur naturally as part of the encoding for a character.
486 | *
487 | * The given data (separator) parameter should be immutable.
488 | * For performance reasons, the socket will retain it, not copy it.
489 | * So if it is immutable, don't modify it while the socket is using it.
490 | **/
491 | - (void)readDataToData:(NSData *)data withTimeout:(NSTimeInterval)timeout tag:(long)tag;
492 |
493 | /**
494 | * Reads bytes until (and including) the passed "data" parameter, which acts as a separator.
495 | * The bytes will be appended to the given byte buffer starting at the given offset.
496 | * The given buffer will automatically be increased in size if needed.
497 | *
498 | * If the timeout value is negative, the read operation will not use a timeout.
499 | * If the buffer if nil, a buffer will automatically be created for you.
500 | *
501 | * If the bufferOffset is greater than the length of the given buffer,
502 | * the method will do nothing (except maybe print a warning), and the delegate will not be called.
503 | *
504 | * If you pass a buffer, you must not alter it in any way while the socket is using it.
505 | * After completion, the data returned in socket:didReadData:withTag: will be a subset of the given buffer.
506 | * That is, it will reference the bytes that were appended to the given buffer via
507 | * the method [NSData dataWithBytesNoCopy:length:freeWhenDone:NO].
508 | *
509 | * To read a line from the socket, use the line separator (e.g. CRLF for HTTP, see below) as the "data" parameter.
510 | * If you're developing your own custom protocol, be sure your separator can not occur naturally as
511 | * part of the data between separators.
512 | * For example, imagine you want to send several small documents over a socket.
513 | * Using CRLF as a separator is likely unwise, as a CRLF could easily exist within the documents.
514 | * In this particular example, it would be better to use a protocol similar to HTTP with
515 | * a header that includes the length of the document.
516 | * Also be careful that your separator cannot occur naturally as part of the encoding for a character.
517 | *
518 | * The given data (separator) parameter should be immutable.
519 | * For performance reasons, the socket will retain it, not copy it.
520 | * So if it is immutable, don't modify it while the socket is using it.
521 | **/
522 | - (void)readDataToData:(NSData *)data
523 | withTimeout:(NSTimeInterval)timeout
524 | buffer:(NSMutableData *)buffer
525 | bufferOffset:(NSUInteger)offset
526 | tag:(long)tag;
527 |
528 | /**
529 | * Reads bytes until (and including) the passed "data" parameter, which acts as a separator.
530 | *
531 | * If the timeout value is negative, the read operation will not use a timeout.
532 | *
533 | * If maxLength is zero, no length restriction is enforced.
534 | * Otherwise if maxLength bytes are read without completing the read,
535 | * it is treated similarly to a timeout - the socket is closed with a GCDAsyncSocketReadMaxedOutError.
536 | * The read will complete successfully if exactly maxLength bytes are read and the given data is found at the end.
537 | *
538 | * If you pass nil or zero-length data as the "data" parameter,
539 | * the method will do nothing (except maybe print a warning), and the delegate will not be called.
540 | * If you pass a maxLength parameter that is less than the length of the data parameter,
541 | * the method will do nothing (except maybe print a warning), and the delegate will not be called.
542 | *
543 | * To read a line from the socket, use the line separator (e.g. CRLF for HTTP, see below) as the "data" parameter.
544 | * If you're developing your own custom protocol, be sure your separator can not occur naturally as
545 | * part of the data between separators.
546 | * For example, imagine you want to send several small documents over a socket.
547 | * Using CRLF as a separator is likely unwise, as a CRLF could easily exist within the documents.
548 | * In this particular example, it would be better to use a protocol similar to HTTP with
549 | * a header that includes the length of the document.
550 | * Also be careful that your separator cannot occur naturally as part of the encoding for a character.
551 | *
552 | * The given data (separator) parameter should be immutable.
553 | * For performance reasons, the socket will retain it, not copy it.
554 | * So if it is immutable, don't modify it while the socket is using it.
555 | **/
556 | - (void)readDataToData:(NSData *)data withTimeout:(NSTimeInterval)timeout maxLength:(NSUInteger)length tag:(long)tag;
557 |
558 | /**
559 | * Reads bytes until (and including) the passed "data" parameter, which acts as a separator.
560 | * The bytes will be appended to the given byte buffer starting at the given offset.
561 | * The given buffer will automatically be increased in size if needed.
562 | *
563 | * If the timeout value is negative, the read operation will not use a timeout.
564 | * If the buffer if nil, a buffer will automatically be created for you.
565 | *
566 | * If maxLength is zero, no length restriction is enforced.
567 | * Otherwise if maxLength bytes are read without completing the read,
568 | * it is treated similarly to a timeout - the socket is closed with a GCDAsyncSocketReadMaxedOutError.
569 | * The read will complete successfully if exactly maxLength bytes are read and the given data is found at the end.
570 | *
571 | * If you pass a maxLength parameter that is less than the length of the data (separator) parameter,
572 | * the method will do nothing (except maybe print a warning), and the delegate will not be called.
573 | * If the bufferOffset is greater than the length of the given buffer,
574 | * the method will do nothing (except maybe print a warning), and the delegate will not be called.
575 | *
576 | * If you pass a buffer, you must not alter it in any way while the socket is using it.
577 | * After completion, the data returned in socket:didReadData:withTag: will be a subset of the given buffer.
578 | * That is, it will reference the bytes that were appended to the given buffer via
579 | * the method [NSData dataWithBytesNoCopy:length:freeWhenDone:NO].
580 | *
581 | * To read a line from the socket, use the line separator (e.g. CRLF for HTTP, see below) as the "data" parameter.
582 | * If you're developing your own custom protocol, be sure your separator can not occur naturally as
583 | * part of the data between separators.
584 | * For example, imagine you want to send several small documents over a socket.
585 | * Using CRLF as a separator is likely unwise, as a CRLF could easily exist within the documents.
586 | * In this particular example, it would be better to use a protocol similar to HTTP with
587 | * a header that includes the length of the document.
588 | * Also be careful that your separator cannot occur naturally as part of the encoding for a character.
589 | *
590 | * The given data (separator) parameter should be immutable.
591 | * For performance reasons, the socket will retain it, not copy it.
592 | * So if it is immutable, don't modify it while the socket is using it.
593 | **/
594 | - (void)readDataToData:(NSData *)data
595 | withTimeout:(NSTimeInterval)timeout
596 | buffer:(NSMutableData *)buffer
597 | bufferOffset:(NSUInteger)offset
598 | maxLength:(NSUInteger)length
599 | tag:(long)tag;
600 |
601 | /**
602 | * Returns progress of the current read, from 0.0 to 1.0, or NaN if no current read (use isnan() to check).
603 | * The parameters "tag", "done" and "total" will be filled in if they aren't NULL.
604 | **/
605 | - (float)progressOfReadReturningTag:(long *)tagPtr bytesDone:(NSUInteger *)donePtr total:(NSUInteger *)totalPtr;
606 |
607 | #pragma mark Writing
608 |
609 | /**
610 | * Writes data to the socket, and calls the delegate when finished.
611 | *
612 | * If you pass in nil or zero-length data, this method does nothing and the delegate will not be called.
613 | * If the timeout value is negative, the write operation will not use a timeout.
614 | *
615 | * Thread-Safety Note:
616 | * If the given data parameter is mutable (NSMutableData) then you MUST NOT alter the data while
617 | * the socket is writing it. In other words, it's not safe to alter the data until after the delegate method
618 | * socket:didWriteDataWithTag: is invoked signifying that this particular write operation has completed.
619 | * This is due to the fact that GCDAsyncSocket does NOT copy the data. It simply retains it.
620 | * This is for performance reasons. Often times, if NSMutableData is passed, it is because
621 | * a request/response was built up in memory. Copying this data adds an unwanted/unneeded overhead.
622 | * If you need to write data from an immutable buffer, and you need to alter the buffer before the socket
623 | * completes writing the bytes (which is NOT immediately after this method returns, but rather at a later time
624 | * when the delegate method notifies you), then you should first copy the bytes, and pass the copy to this method.
625 | **/
626 | - (void)writeData:(NSData *)data withTimeout:(NSTimeInterval)timeout tag:(long)tag;
627 |
628 | /**
629 | * Returns progress of the current write, from 0.0 to 1.0, or NaN if no current write (use isnan() to check).
630 | * The parameters "tag", "done" and "total" will be filled in if they aren't NULL.
631 | **/
632 | - (float)progressOfWriteReturningTag:(long *)tagPtr bytesDone:(NSUInteger *)donePtr total:(NSUInteger *)totalPtr;
633 |
634 | #pragma mark Security
635 |
636 | /**
637 | * Secures the connection using SSL/TLS.
638 | *
639 | * This method may be called at any time, and the TLS handshake will occur after all pending reads and writes
640 | * are finished. This allows one the option of sending a protocol dependent StartTLS message, and queuing
641 | * the upgrade to TLS at the same time, without having to wait for the write to finish.
642 | * Any reads or writes scheduled after this method is called will occur over the secured connection.
643 | *
644 | * ==== The available TOP-LEVEL KEYS are:
645 | *
646 | * - GCDAsyncSocketManuallyEvaluateTrust
647 | * The value must be of type NSNumber, encapsulating a BOOL value.
648 | * If you set this to YES, then the underlying SecureTransport system will not evaluate the SecTrustRef of the peer.
649 | * Instead it will pause at the moment evaulation would typically occur,
650 | * and allow us to handle the security evaluation however we see fit.
651 | * So GCDAsyncSocket will invoke the delegate method socket:shouldTrustPeer: passing the SecTrustRef.
652 | *
653 | * Note that if you set this option, then all other configuration keys are ignored.
654 | * Evaluation will be completely up to you during the socket:didReceiveTrust:completionHandler: delegate method.
655 | *
656 | * For more information on trust evaluation see:
657 | * Apple's Technical Note TN2232 - HTTPS Server Trust Evaluation
658 | * https://developer.apple.com/library/ios/technotes/tn2232/_index.html
659 | *
660 | * If unspecified, the default value is NO.
661 | *
662 | * - GCDAsyncSocketUseCFStreamForTLS (iOS only)
663 | * The value must be of type NSNumber, encapsulating a BOOL value.
664 | * By default GCDAsyncSocket will use the SecureTransport layer to perform encryption.
665 | * This gives us more control over the security protocol (many more configuration options),
666 | * plus it allows us to optimize things like sys calls and buffer allocation.
667 | *
668 | * However, if you absolutely must, you can instruct GCDAsyncSocket to use the old-fashioned encryption
669 | * technique by going through the CFStream instead. So instead of using SecureTransport, GCDAsyncSocket
670 | * will instead setup a CFRead/CFWriteStream. And then set the kCFStreamPropertySSLSettings property
671 | * (via CFReadStreamSetProperty / CFWriteStreamSetProperty) and will pass the given options to this method.
672 | *
673 | * Thus all the other keys in the given dictionary will be ignored by GCDAsyncSocket,
674 | * and will passed directly CFReadStreamSetProperty / CFWriteStreamSetProperty.
675 | * For more infomation on these keys, please see the documentation for kCFStreamPropertySSLSettings.
676 | *
677 | * If unspecified, the default value is NO.
678 | *
679 | * ==== The available CONFIGURATION KEYS are:
680 | *
681 | * - kCFStreamSSLPeerName
682 | * The value must be of type NSString.
683 | * It should match the name in the X.509 certificate given by the remote party.
684 | * See Apple's documentation for SSLSetPeerDomainName.
685 | *
686 | * - kCFStreamSSLCertificates
687 | * The value must be of type NSArray.
688 | * See Apple's documentation for SSLSetCertificate.
689 | *
690 | * - kCFStreamSSLIsServer
691 | * The value must be of type NSNumber, encapsulationg a BOOL value.
692 | * See Apple's documentation for SSLCreateContext for iOS.
693 | * This is optional for iOS. If not supplied, a NO value is the default.
694 | * This is not needed for Mac OS X, and the value is ignored.
695 | *
696 | * - GCDAsyncSocketSSLPeerID
697 | * The value must be of type NSData.
698 | * You must set this value if you want to use TLS session resumption.
699 | * See Apple's documentation for SSLSetPeerID.
700 | *
701 | * - GCDAsyncSocketSSLProtocolVersionMin
702 | * - GCDAsyncSocketSSLProtocolVersionMax
703 | * The value(s) must be of type NSNumber, encapsulting a SSLProtocol value.
704 | * See Apple's documentation for SSLSetProtocolVersionMin & SSLSetProtocolVersionMax.
705 | * See also the SSLProtocol typedef.
706 | *
707 | * - GCDAsyncSocketSSLSessionOptionFalseStart
708 | * The value must be of type NSNumber, encapsulating a BOOL value.
709 | * See Apple's documentation for kSSLSessionOptionFalseStart.
710 | *
711 | * - GCDAsyncSocketSSLSessionOptionSendOneByteRecord
712 | * The value must be of type NSNumber, encapsulating a BOOL value.
713 | * See Apple's documentation for kSSLSessionOptionSendOneByteRecord.
714 | *
715 | * - GCDAsyncSocketSSLCipherSuites
716 | * The values must be of type NSArray.
717 | * Each item within the array must be a NSNumber, encapsulating
718 | * See Apple's documentation for SSLSetEnabledCiphers.
719 | * See also the SSLCipherSuite typedef.
720 | *
721 | * - GCDAsyncSocketSSLDiffieHellmanParameters (Mac OS X only)
722 | * The value must be of type NSData.
723 | * See Apple's documentation for SSLSetDiffieHellmanParams.
724 | *
725 | * ==== The following UNAVAILABLE KEYS are: (with throw an exception)
726 | *
727 | * - kCFStreamSSLAllowsAnyRoot (UNAVAILABLE)
728 | * You MUST use manual trust evaluation instead (see GCDAsyncSocketManuallyEvaluateTrust).
729 | * Corresponding deprecated method: SSLSetAllowsAnyRoot
730 | *
731 | * - kCFStreamSSLAllowsExpiredRoots (UNAVAILABLE)
732 | * You MUST use manual trust evaluation instead (see GCDAsyncSocketManuallyEvaluateTrust).
733 | * Corresponding deprecated method: SSLSetAllowsExpiredRoots
734 | *
735 | * - kCFStreamSSLAllowsExpiredCertificates (UNAVAILABLE)
736 | * You MUST use manual trust evaluation instead (see GCDAsyncSocketManuallyEvaluateTrust).
737 | * Corresponding deprecated method: SSLSetAllowsExpiredCerts
738 | *
739 | * - kCFStreamSSLValidatesCertificateChain (UNAVAILABLE)
740 | * You MUST use manual trust evaluation instead (see GCDAsyncSocketManuallyEvaluateTrust).
741 | * Corresponding deprecated method: SSLSetEnableCertVerify
742 | *
743 | * - kCFStreamSSLLevel (UNAVAILABLE)
744 | * You MUST use GCDAsyncSocketSSLProtocolVersionMin & GCDAsyncSocketSSLProtocolVersionMin instead.
745 | * Corresponding deprecated method: SSLSetProtocolVersionEnabled
746 | *
747 | *
748 | * Please refer to Apple's documentation for corresponding SSLFunctions.
749 | *
750 | * If you pass in nil or an empty dictionary, the default settings will be used.
751 | *
752 | * IMPORTANT SECURITY NOTE:
753 | * The default settings will check to make sure the remote party's certificate is signed by a
754 | * trusted 3rd party certificate agency (e.g. verisign) and that the certificate is not expired.
755 | * However it will not verify the name on the certificate unless you
756 | * give it a name to verify against via the kCFStreamSSLPeerName key.
757 | * The security implications of this are important to understand.
758 | * Imagine you are attempting to create a secure connection to MySecureServer.com,
759 | * but your socket gets directed to MaliciousServer.com because of a hacked DNS server.
760 | * If you simply use the default settings, and MaliciousServer.com has a valid certificate,
761 | * the default settings will not detect any problems since the certificate is valid.
762 | * To properly secure your connection in this particular scenario you
763 | * should set the kCFStreamSSLPeerName property to "MySecureServer.com".
764 | *
765 | * You can also perform additional validation in socketDidSecure.
766 | **/
767 | - (void)startTLS:(NSDictionary *)tlsSettings;
768 |
769 | #pragma mark Advanced
770 |
771 | /**
772 | * Traditionally sockets are not closed until the conversation is over.
773 | * However, it is technically possible for the remote enpoint to close its write stream.
774 | * Our socket would then be notified that there is no more data to be read,
775 | * but our socket would still be writeable and the remote endpoint could continue to receive our data.
776 | *
777 | * The argument for this confusing functionality stems from the idea that a client could shut down its
778 | * write stream after sending a request to the server, thus notifying the server there are to be no further requests.
779 | * In practice, however, this technique did little to help server developers.
780 | *
781 | * To make matters worse, from a TCP perspective there is no way to tell the difference from a read stream close
782 | * and a full socket close. They both result in the TCP stack receiving a FIN packet. The only way to tell
783 | * is by continuing to write to the socket. If it was only a read stream close, then writes will continue to work.
784 | * Otherwise an error will be occur shortly (when the remote end sends us a RST packet).
785 | *
786 | * In addition to the technical challenges and confusion, many high level socket/stream API's provide
787 | * no support for dealing with the problem. If the read stream is closed, the API immediately declares the
788 | * socket to be closed, and shuts down the write stream as well. In fact, this is what Apple's CFStream API does.
789 | * It might sound like poor design at first, but in fact it simplifies development.
790 | *
791 | * The vast majority of the time if the read stream is closed it's because the remote endpoint closed its socket.
792 | * Thus it actually makes sense to close the socket at this point.
793 | * And in fact this is what most networking developers want and expect to happen.
794 | * However, if you are writing a server that interacts with a plethora of clients,
795 | * you might encounter a client that uses the discouraged technique of shutting down its write stream.
796 | * If this is the case, you can set this property to NO,
797 | * and make use of the socketDidCloseReadStream delegate method.
798 | *
799 | * The default value is YES.
800 | **/
801 | @property (atomic, assign, readwrite) BOOL autoDisconnectOnClosedReadStream;
802 |
803 | /**
804 | * GCDAsyncSocket maintains thread safety by using an internal serial dispatch_queue.
805 | * In most cases, the instance creates this queue itself.
806 | * However, to allow for maximum flexibility, the internal queue may be passed in the init method.
807 | * This allows for some advanced options such as controlling socket priority via target queues.
808 | * However, when one begins to use target queues like this, they open the door to some specific deadlock issues.
809 | *
810 | * For example, imagine there are 2 queues:
811 | * dispatch_queue_t socketQueue;
812 | * dispatch_queue_t socketTargetQueue;
813 | *
814 | * If you do this (pseudo-code):
815 | * socketQueue.targetQueue = socketTargetQueue;
816 | *
817 | * Then all socketQueue operations will actually get run on the given socketTargetQueue.
818 | * This is fine and works great in most situations.
819 | * But if you run code directly from within the socketTargetQueue that accesses the socket,
820 | * you could potentially get deadlock. Imagine the following code:
821 | *
822 | * - (BOOL)socketHasSomething
823 | * {
824 | * __block BOOL result = NO;
825 | * dispatch_block_t block = ^{
826 | * result = [self someInternalMethodToBeRunOnlyOnSocketQueue];
827 | * }
828 | * if (is_executing_on_queue(socketQueue))
829 | * block();
830 | * else
831 | * dispatch_sync(socketQueue, block);
832 | *
833 | * return result;
834 | * }
835 | *
836 | * What happens if you call this method from the socketTargetQueue? The result is deadlock.
837 | * This is because the GCD API offers no mechanism to discover a queue's targetQueue.
838 | * Thus we have no idea if our socketQueue is configured with a targetQueue.
839 | * If we had this information, we could easily avoid deadlock.
840 | * But, since these API's are missing or unfeasible, you'll have to explicitly set it.
841 | *
842 | * IF you pass a socketQueue via the init method,
843 | * AND you've configured the passed socketQueue with a targetQueue,
844 | * THEN you should pass the end queue in the target hierarchy.
845 | *
846 | * For example, consider the following queue hierarchy:
847 | * socketQueue -> ipQueue -> moduleQueue
848 | *
849 | * This example demonstrates priority shaping within some server.
850 | * All incoming client connections from the same IP address are executed on the same target queue.
851 | * And all connections for a particular module are executed on the same target queue.
852 | * Thus, the priority of all networking for the entire module can be changed on the fly.
853 | * Additionally, networking traffic from a single IP cannot monopolize the module.
854 | *
855 | * Here's how you would accomplish something like that:
856 | * - (dispatch_queue_t)newSocketQueueForConnectionFromAddress:(NSData *)address onSocket:(GCDAsyncSocket *)sock
857 | * {
858 | * dispatch_queue_t socketQueue = dispatch_queue_create("", NULL);
859 | * dispatch_queue_t ipQueue = [self ipQueueForAddress:address];
860 | *
861 | * dispatch_set_target_queue(socketQueue, ipQueue);
862 | * dispatch_set_target_queue(iqQueue, moduleQueue);
863 | *
864 | * return socketQueue;
865 | * }
866 | * - (void)socket:(GCDAsyncSocket *)sock didAcceptNewSocket:(GCDAsyncSocket *)newSocket
867 | * {
868 | * [clientConnections addObject:newSocket];
869 | * [newSocket markSocketQueueTargetQueue:moduleQueue];
870 | * }
871 | *
872 | * Note: This workaround is ONLY needed if you intend to execute code directly on the ipQueue or moduleQueue.
873 | * This is often NOT the case, as such queues are used solely for execution shaping.
874 | **/
875 | - (void)markSocketQueueTargetQueue:(dispatch_queue_t)socketQueuesPreConfiguredTargetQueue;
876 | - (void)unmarkSocketQueueTargetQueue:(dispatch_queue_t)socketQueuesPreviouslyConfiguredTargetQueue;
877 |
878 | /**
879 | * It's not thread-safe to access certain variables from outside the socket's internal queue.
880 | *
881 | * For example, the socket file descriptor.
882 | * File descriptors are simply integers which reference an index in the per-process file table.
883 | * However, when one requests a new file descriptor (by opening a file or socket),
884 | * the file descriptor returned is guaranteed to be the lowest numbered unused descriptor.
885 | * So if we're not careful, the following could be possible:
886 | *
887 | * - Thread A invokes a method which returns the socket's file descriptor.
888 | * - The socket is closed via the socket's internal queue on thread B.
889 | * - Thread C opens a file, and subsequently receives the file descriptor that was previously the socket's FD.
890 | * - Thread A is now accessing/altering the file instead of the socket.
891 | *
892 | * In addition to this, other variables are not actually objects,
893 | * and thus cannot be retained/released or even autoreleased.
894 | * An example is the sslContext, of type SSLContextRef, which is actually a malloc'd struct.
895 | *
896 | * Although there are internal variables that make it difficult to maintain thread-safety,
897 | * it is important to provide access to these variables
898 | * to ensure this class can be used in a wide array of environments.
899 | * This method helps to accomplish this by invoking the current block on the socket's internal queue.
900 | * The methods below can be invoked from within the block to access
901 | * those generally thread-unsafe internal variables in a thread-safe manner.
902 | * The given block will be invoked synchronously on the socket's internal queue.
903 | *
904 | * If you save references to any protected variables and use them outside the block, you do so at your own peril.
905 | **/
906 | - (void)performBlock:(dispatch_block_t)block;
907 |
908 | /**
909 | * These methods are only available from within the context of a performBlock: invocation.
910 | * See the documentation for the performBlock: method above.
911 | *
912 | * Provides access to the socket's file descriptor(s).
913 | * If the socket is a server socket (is accepting incoming connections),
914 | * it might actually have multiple internal socket file descriptors - one for IPv4 and one for IPv6.
915 | **/
916 | - (int)socketFD;
917 | - (int)socket4FD;
918 | - (int)socket6FD;
919 |
920 | #if TARGET_OS_IPHONE
921 |
922 | /**
923 | * These methods are only available from within the context of a performBlock: invocation.
924 | * See the documentation for the performBlock: method above.
925 | *
926 | * Provides access to the socket's internal CFReadStream/CFWriteStream.
927 | *
928 | * These streams are only used as workarounds for specific iOS shortcomings:
929 | *
930 | * - Apple has decided to keep the SecureTransport framework private is iOS.
931 | * This means the only supplied way to do SSL/TLS is via CFStream or some other API layered on top of it.
932 | * Thus, in order to provide SSL/TLS support on iOS we are forced to rely on CFStream,
933 | * instead of the preferred and faster and more powerful SecureTransport.
934 | *
935 | * - If a socket doesn't have backgrounding enabled, and that socket is closed while the app is backgrounded,
936 | * Apple only bothers to notify us via the CFStream API.
937 | * The faster and more powerful GCD API isn't notified properly in this case.
938 | *
939 | * See also: (BOOL)enableBackgroundingOnSocket
940 | **/
941 | - (CFReadStreamRef)readStream;
942 | - (CFWriteStreamRef)writeStream;
943 |
944 | /**
945 | * This method is only available from within the context of a performBlock: invocation.
946 | * See the documentation for the performBlock: method above.
947 | *
948 | * Configures the socket to allow it to operate when the iOS application has been backgrounded.
949 | * In other words, this method creates a read & write stream, and invokes:
950 | *
951 | * CFReadStreamSetProperty(readStream, kCFStreamNetworkServiceType, kCFStreamNetworkServiceTypeVoIP);
952 | * CFWriteStreamSetProperty(writeStream, kCFStreamNetworkServiceType, kCFStreamNetworkServiceTypeVoIP);
953 | *
954 | * Returns YES if successful, NO otherwise.
955 | *
956 | * Note: Apple does not officially support backgrounding server sockets.
957 | * That is, if your socket is accepting incoming connections, Apple does not officially support
958 | * allowing iOS applications to accept incoming connections while an app is backgrounded.
959 | *
960 | * Example usage:
961 | *
962 | * - (void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(uint16_t)port
963 | * {
964 | * [asyncSocket performBlock:^{
965 | * [asyncSocket enableBackgroundingOnSocket];
966 | * }];
967 | * }
968 | **/
969 | - (BOOL)enableBackgroundingOnSocket;
970 |
971 | #endif
972 |
973 | /**
974 | * This method is only available from within the context of a performBlock: invocation.
975 | * See the documentation for the performBlock: method above.
976 | *
977 | * Provides access to the socket's SSLContext, if SSL/TLS has been started on the socket.
978 | **/
979 | - (SSLContextRef)sslContext;
980 |
981 | #pragma mark Utilities
982 |
983 | /**
984 | * The address lookup utility used by the class.
985 | * This method is synchronous, so it's recommended you use it on a background thread/queue.
986 | *
987 | * The special strings "localhost" and "loopback" return the loopback address for IPv4 and IPv6.
988 | *
989 | * @returns
990 | * A mutable array with all IPv4 and IPv6 addresses returned by getaddrinfo.
991 | * The addresses are specifically for TCP connections.
992 | * You can filter the addresses, if needed, using the other utility methods provided by the class.
993 | **/
994 | + (NSMutableArray *)lookupHost:(NSString *)host port:(uint16_t)port error:(NSError **)errPtr;
995 |
996 | /**
997 | * Extracting host and port information from raw address data.
998 | **/
999 |
1000 | + (NSString *)hostFromAddress:(NSData *)address;
1001 | + (uint16_t)portFromAddress:(NSData *)address;
1002 |
1003 | + (BOOL)isIPv4Address:(NSData *)address;
1004 | + (BOOL)isIPv6Address:(NSData *)address;
1005 |
1006 | + (BOOL)getHost:(NSString **)hostPtr port:(uint16_t *)portPtr fromAddress:(NSData *)address;
1007 |
1008 | + (BOOL)getHost:(NSString **)hostPtr port:(uint16_t *)portPtr family:(sa_family_t *)afPtr fromAddress:(NSData *)address;
1009 |
1010 | /**
1011 | * A few common line separators, for use with the readDataToData:... methods.
1012 | **/
1013 | + (NSData *)CRLFData; // 0x0D0A
1014 | + (NSData *)CRData; // 0x0D
1015 | + (NSData *)LFData; // 0x0A
1016 | + (NSData *)ZeroData; // 0x00
1017 |
1018 | @end
1019 |
1020 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1021 | #pragma mark -
1022 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1023 |
1024 | @protocol GCDAsyncSocketDelegate
1025 | @optional
1026 |
1027 | /**
1028 | * This method is called immediately prior to socket:didAcceptNewSocket:.
1029 | * It optionally allows a listening socket to specify the socketQueue for a new accepted socket.
1030 | * If this method is not implemented, or returns NULL, the new accepted socket will create its own default queue.
1031 | *
1032 | * Since you cannot autorelease a dispatch_queue,
1033 | * this method uses the "new" prefix in its name to specify that the returned queue has been retained.
1034 | *
1035 | * Thus you could do something like this in the implementation:
1036 | * return dispatch_queue_create("MyQueue", NULL);
1037 | *
1038 | * If you are placing multiple sockets on the same queue,
1039 | * then care should be taken to increment the retain count each time this method is invoked.
1040 | *
1041 | * For example, your implementation might look something like this:
1042 | * dispatch_retain(myExistingQueue);
1043 | * return myExistingQueue;
1044 | **/
1045 | - (dispatch_queue_t)newSocketQueueForConnectionFromAddress:(NSData *)address onSocket:(GCDAsyncSocket *)sock;
1046 |
1047 | /**
1048 | * Called when a socket accepts a connection.
1049 | * Another socket is automatically spawned to handle it.
1050 | *
1051 | * You must retain the newSocket if you wish to handle the connection.
1052 | * Otherwise the newSocket instance will be released and the spawned connection will be closed.
1053 | *
1054 | * By default the new socket will have the same delegate and delegateQueue.
1055 | * You may, of course, change this at any time.
1056 | **/
1057 | - (void)socket:(GCDAsyncSocket *)sock didAcceptNewSocket:(GCDAsyncSocket *)newSocket;
1058 |
1059 | /**
1060 | * Called when a socket connects and is ready for reading and writing.
1061 | * The host parameter will be an IP address, not a DNS name.
1062 | **/
1063 | - (void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(uint16_t)port;
1064 |
1065 | /**
1066 | * Called when a socket has completed reading the requested data into memory.
1067 | * Not called if there is an error.
1068 | **/
1069 | - (void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag;
1070 |
1071 | /**
1072 | * Called when a socket has read in data, but has not yet completed the read.
1073 | * This would occur if using readToData: or readToLength: methods.
1074 | * It may be used to for things such as updating progress bars.
1075 | **/
1076 | - (void)socket:(GCDAsyncSocket *)sock didReadPartialDataOfLength:(NSUInteger)partialLength tag:(long)tag;
1077 |
1078 | /**
1079 | * Called when a socket has completed writing the requested data. Not called if there is an error.
1080 | **/
1081 | - (void)socket:(GCDAsyncSocket *)sock didWriteDataWithTag:(long)tag;
1082 |
1083 | /**
1084 | * Called when a socket has written some data, but has not yet completed the entire write.
1085 | * It may be used to for things such as updating progress bars.
1086 | **/
1087 | - (void)socket:(GCDAsyncSocket *)sock didWritePartialDataOfLength:(NSUInteger)partialLength tag:(long)tag;
1088 |
1089 | /**
1090 | * Called if a read operation has reached its timeout without completing.
1091 | * This method allows you to optionally extend the timeout.
1092 | * If you return a positive time interval (> 0) the read's timeout will be extended by the given amount.
1093 | * If you don't implement this method, or return a non-positive time interval (<= 0) the read will timeout as usual.
1094 | *
1095 | * The elapsed parameter is the sum of the original timeout, plus any additions previously added via this method.
1096 | * The length parameter is the number of bytes that have been read so far for the read operation.
1097 | *
1098 | * Note that this method may be called multiple times for a single read if you return positive numbers.
1099 | **/
1100 | - (NSTimeInterval)socket:(GCDAsyncSocket *)sock shouldTimeoutReadWithTag:(long)tag
1101 | elapsed:(NSTimeInterval)elapsed
1102 | bytesDone:(NSUInteger)length;
1103 |
1104 | /**
1105 | * Called if a write operation has reached its timeout without completing.
1106 | * This method allows you to optionally extend the timeout.
1107 | * If you return a positive time interval (> 0) the write's timeout will be extended by the given amount.
1108 | * If you don't implement this method, or return a non-positive time interval (<= 0) the write will timeout as usual.
1109 | *
1110 | * The elapsed parameter is the sum of the original timeout, plus any additions previously added via this method.
1111 | * The length parameter is the number of bytes that have been written so far for the write operation.
1112 | *
1113 | * Note that this method may be called multiple times for a single write if you return positive numbers.
1114 | **/
1115 | - (NSTimeInterval)socket:(GCDAsyncSocket *)sock shouldTimeoutWriteWithTag:(long)tag
1116 | elapsed:(NSTimeInterval)elapsed
1117 | bytesDone:(NSUInteger)length;
1118 |
1119 | /**
1120 | * Conditionally called if the read stream closes, but the write stream may still be writeable.
1121 | *
1122 | * This delegate method is only called if autoDisconnectOnClosedReadStream has been set to NO.
1123 | * See the discussion on the autoDisconnectOnClosedReadStream method for more information.
1124 | **/
1125 | - (void)socketDidCloseReadStream:(GCDAsyncSocket *)sock;
1126 |
1127 | /**
1128 | * Called when a socket disconnects with or without error.
1129 | *
1130 | * If you call the disconnect method, and the socket wasn't already disconnected,
1131 | * then an invocation of this delegate method will be enqueued on the delegateQueue
1132 | * before the disconnect method returns.
1133 | *
1134 | * Note: If the GCDAsyncSocket instance is deallocated while it is still connected,
1135 | * and the delegate is not also deallocated, then this method will be invoked,
1136 | * but the sock parameter will be nil. (It must necessarily be nil since it is no longer available.)
1137 | * This is a generally rare, but is possible if one writes code like this:
1138 | *
1139 | * asyncSocket = nil; // I'm implicitly disconnecting the socket
1140 | *
1141 | * In this case it may preferrable to nil the delegate beforehand, like this:
1142 | *
1143 | * asyncSocket.delegate = nil; // Don't invoke my delegate method
1144 | * asyncSocket = nil; // I'm implicitly disconnecting the socket
1145 | *
1146 | * Of course, this depends on how your state machine is configured.
1147 | **/
1148 | - (void)socketDidDisconnect:(GCDAsyncSocket *)sock withError:(NSError *)err;
1149 |
1150 | /**
1151 | * Called after the socket has successfully completed SSL/TLS negotiation.
1152 | * This method is not called unless you use the provided startTLS method.
1153 | *
1154 | * If a SSL/TLS negotiation fails (invalid certificate, etc) then the socket will immediately close,
1155 | * and the socketDidDisconnect:withError: delegate method will be called with the specific SSL error code.
1156 | **/
1157 | - (void)socketDidSecure:(GCDAsyncSocket *)sock;
1158 |
1159 | /**
1160 | * Allows a socket delegate to hook into the TLS handshake and manually validate the peer it's connecting to.
1161 | *
1162 | * This is only called if startTLS is invoked with options that include:
1163 | * - GCDAsyncSocketManuallyEvaluateTrust == YES
1164 | *
1165 | * Typically the delegate will use SecTrustEvaluate (and related functions) to properly validate the peer.
1166 | *
1167 | * Note from Apple's documentation:
1168 | * Because [SecTrustEvaluate] might look on the network for certificates in the certificate chain,
1169 | * [it] might block while attempting network access. You should never call it from your main thread;
1170 | * call it only from within a function running on a dispatch queue or on a separate thread.
1171 | *
1172 | * Thus this method uses a completionHandler block rather than a normal return value.
1173 | * The completionHandler block is thread-safe, and may be invoked from a background queue/thread.
1174 | * It is safe to invoke the completionHandler block even if the socket has been closed.
1175 | **/
1176 | - (void)socket:(GCDAsyncSocket *)sock didReceiveTrust:(SecTrustRef)trust
1177 | completionHandler:(void (^)(BOOL shouldTrustPeer))completionHandler;
1178 |
1179 | @end
1180 |
--------------------------------------------------------------------------------