├── .gitignore
├── AnyBar
├── Resources
│ ├── blue@2x.png
│ ├── cyan@2x.png
│ ├── red@2x.png
│ ├── black@2x.png
│ ├── green@2x.png
│ ├── orange@2x.png
│ ├── purple@2x.png
│ ├── white@2x.png
│ ├── yellow@2x.png
│ ├── black_alt@2x.png
│ ├── question@2x.png
│ ├── screenshot.png
│ ├── white_alt@2x.png
│ ├── exclamation@2x.png
│ └── question_alt@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.h
├── AnyBarApp.m
├── 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
│ │ └── AnyBar.xccheckout
├── xcuserdata
│ └── prokopov.xcuserdatad
│ │ └── xcschemes
│ │ ├── xcschememanagement.plist
│ │ └── AnyBar.xcscheme
└── project.pbxproj
├── README.md
└── LICENSE
/.gitignore:
--------------------------------------------------------------------------------
1 | xcuserdata
2 | *.xcuserdatad
3 | build
4 |
--------------------------------------------------------------------------------
/AnyBar/Resources/blue@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ttscoff/AnyBar/master/AnyBar/Resources/blue@2x.png
--------------------------------------------------------------------------------
/AnyBar/Resources/cyan@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ttscoff/AnyBar/master/AnyBar/Resources/cyan@2x.png
--------------------------------------------------------------------------------
/AnyBar/Resources/red@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ttscoff/AnyBar/master/AnyBar/Resources/red@2x.png
--------------------------------------------------------------------------------
/AnyBar/Resources/black@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ttscoff/AnyBar/master/AnyBar/Resources/black@2x.png
--------------------------------------------------------------------------------
/AnyBar/Resources/green@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ttscoff/AnyBar/master/AnyBar/Resources/green@2x.png
--------------------------------------------------------------------------------
/AnyBar/Resources/orange@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ttscoff/AnyBar/master/AnyBar/Resources/orange@2x.png
--------------------------------------------------------------------------------
/AnyBar/Resources/purple@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ttscoff/AnyBar/master/AnyBar/Resources/purple@2x.png
--------------------------------------------------------------------------------
/AnyBar/Resources/white@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ttscoff/AnyBar/master/AnyBar/Resources/white@2x.png
--------------------------------------------------------------------------------
/AnyBar/Resources/yellow@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ttscoff/AnyBar/master/AnyBar/Resources/yellow@2x.png
--------------------------------------------------------------------------------
/AnyBar/Resources/black_alt@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ttscoff/AnyBar/master/AnyBar/Resources/black_alt@2x.png
--------------------------------------------------------------------------------
/AnyBar/Resources/question@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ttscoff/AnyBar/master/AnyBar/Resources/question@2x.png
--------------------------------------------------------------------------------
/AnyBar/Resources/screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ttscoff/AnyBar/master/AnyBar/Resources/screenshot.png
--------------------------------------------------------------------------------
/AnyBar/Resources/white_alt@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ttscoff/AnyBar/master/AnyBar/Resources/white_alt@2x.png
--------------------------------------------------------------------------------
/Tests/test-osa-script.applescript:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ttscoff/AnyBar/master/Tests/test-osa-script.applescript
--------------------------------------------------------------------------------
/AnyBar/Resources/exclamation@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ttscoff/AnyBar/master/AnyBar/Resources/exclamation@2x.png
--------------------------------------------------------------------------------
/AnyBar/Resources/question_alt@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ttscoff/AnyBar/master/AnyBar/Resources/question_alt@2x.png
--------------------------------------------------------------------------------
/AnyBar/Images.xcassets/AppIcon.appiconset/icon_128x128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ttscoff/AnyBar/master/AnyBar/Images.xcassets/AppIcon.appiconset/icon_128x128.png
--------------------------------------------------------------------------------
/AnyBar/Images.xcassets/AppIcon.appiconset/icon_512x512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ttscoff/AnyBar/master/AnyBar/Images.xcassets/AppIcon.appiconset/icon_512x512.png
--------------------------------------------------------------------------------
/AnyBar/Images.xcassets/AppIcon.appiconset/icon_128x128@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ttscoff/AnyBar/master/AnyBar/Images.xcassets/AppIcon.appiconset/icon_128x128@2x.png
--------------------------------------------------------------------------------
/AnyBar/Images.xcassets/AppIcon.appiconset/icon_512x512@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ttscoff/AnyBar/master/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/ttscoff/AnyBar/master/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 |
--------------------------------------------------------------------------------
/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 | - (id)osaTextBridge;
21 | - (void)setOsaTextBridge:(id)textTitle;;
22 | @end
23 |
--------------------------------------------------------------------------------
/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 | - (id)osaText;
22 | - (void)setOsaText:(id)imgName;
23 |
24 | @end
25 |
--------------------------------------------------------------------------------
/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/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 | -(id) osaText {
24 | AppDelegate *delegate = (AppDelegate*)self.delegate;
25 | return [delegate osaTextBridge];
26 | }
27 |
28 | -(void) setOsaText:(id)imgName {
29 | AppDelegate *delegate = (AppDelegate*)self.delegate;
30 | [delegate setOsaTextBridge:imgName];
31 | }
32 |
33 | @end
34 |
--------------------------------------------------------------------------------
/AnyBar/Base.lproj/MainMenu.xib:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/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 | tonsky.$(PRODUCT_NAME:rfc1034identifier)
13 | CFBundleInfoDictionaryVersion
14 | 6.0
15 | CFBundleName
16 | $(PRODUCT_NAME)
17 | CFBundlePackageType
18 | APPL
19 | CFBundleShortVersionString
20 | 0.1.3
21 | CFBundleSignature
22 | ????
23 | CFBundleVersion
24 | 4
25 | LSMinimumSystemVersion
26 | $(MACOSX_DEPLOYMENT_TARGET)
27 | LSUIElement
28 |
29 | NSAppleScriptEnabled
30 | YES
31 | NSHumanReadableCopyright
32 | Copyright © 2015 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 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/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 |
47 |
53 |
54 |
55 |
56 |
57 |
63 |
64 |
65 |
66 |
75 |
76 |
82 |
83 |
84 |
85 |
86 |
87 |
93 |
94 |
100 |
101 |
102 |
103 |
105 |
106 |
109 |
110 |
111 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # AnyBar+text: OS X menubar status indicator
2 |
3 | This project is forked from . Modifications by Brett Terpstra, the original author bears no responsibility for problems I cause.
4 |
5 | > AnyBar is a small indicator for your menubar that does one simple thing: it displays color dot. What color means is up to you. When to change color is also up to you.
6 |
7 |
8 |
9 | *Modifications in this fork:*
10 |
11 | This fork allows a few customizations, including the ability to set text and hide the colored status indicator.
12 |
13 | 1. You can send a string to the UDP port that will set text to the right of the menu item.
14 |
15 | echo -n "red This is the text" | /usr/bin/nc -4u -w0 localhost 1738
16 |
17 | - if the first word of the string is a recognized color name, it will set the indicator color. f there is no color name provided, the color will not be changed
18 | - The remainder of the string will be used to alter the text in the menu bar
19 |
20 | 2. You can use "none" as the color name to remove the indicator
21 | 3. The AppleScript dictionary has a new command for setting text
22 |
23 | tell application "AnyBar" to set title to "This is the text"
24 |
25 | ## Download
26 |
27 | Version 0.1.3 + text:
28 |
29 |
30 |
31 | ## Usage
32 |
33 | AnyBar is controlled via UDP port (1738 by default). Send it a message and it will change a color:
34 |
35 | ```sh
36 | echo -n "black" | nc -4u -w0 localhost 1738
37 | ```
38 |
39 | Following commands change color:
40 |
41 |
42 |
`white`
43 |
`red`
44 |
`orange`
45 |
`yellow`
46 |
`green`
47 |
`cyan`
48 |
`blue`
49 |
`purple`
50 |
`black`
51 |
`question`
52 |
`exclamation`
53 |
54 | And one special command forces AnyBar to quit: `quit`
55 |
56 | ## Alternative clients
57 |
58 | Bash alias:
59 |
60 | ```sh
61 | $ function anybar { echo -n $1 | nc -4u -w0 localhost ${2:-1738}; }
62 |
63 | $ anybar red
64 | $ anybar green 1739
65 | ```
66 |
67 | Go:
68 |
69 | - [justincampbell/anybar](https://github.com/justincampbell/anybar)
70 | - [johntdyer/anybar-go](https://github.com/johntdyer/anybar-go)
71 |
72 | Node:
73 |
74 | - [rumpl/nanybar](https://github.com/rumpl/nanybar)
75 | - [snippet by skibz](https://github.com/tonsky/AnyBar/issues/11)
76 |
77 | PHP:
78 |
79 | - [2bj/Phanybar](https://github.com/2bj/Phanybar)
80 |
81 | Java:
82 |
83 | - [cs475x/AnyBar4j](https://github.com/cs475x/AnyBar4j)
84 |
85 | Python:
86 |
87 | - [philipbl/pyanybar](https://github.com/philipbl/pyAnyBar)
88 |
89 | Ruby:
90 |
91 | - [davydovanton/AnyBar_rb](https://github.com/davydovanton/AnyBar_rb)
92 |
93 | AppleScript:
94 |
95 | ```
96 | tell application "AnyBar" to set image name to "blue"
97 |
98 | tell application "AnyBar" to set current to get image name as Unicode text
99 | display notification current
100 | ```
101 |
102 | ## Integrations
103 |
104 | - Webpack build status plugin [roman01la/anybar-webpack](https://github.com/roman01la/anybar-webpack)
105 | - boot-clj task [tonsky/boot-anybar](https://github.com/tonsky/boot-anybar)
106 |
107 | ## Running multiple instances
108 |
109 | You can run several instances of AnyBar as long as they listen on different ports. Use `ANYBAR_PORT` environment variable to change port and `open -n` to run several instances:
110 |
111 | ```sh
112 | ANYBAR_PORT=1738 open -n ./AnyBar.app
113 | ANYBAR_PORT=1739 open -n ./AnyBar.app
114 | ANYBAR_PORT=1740 open -n ./AnyBar.app
115 | ```
116 |
117 | ## Custom images
118 |
119 | AnyBar can use user-local images if you put them under `~/.AnyBar`. E.g. if you have `~/.AnyBar/square@2x.png` present, send `square` to 1738 and it will be displayed. Images should be 19×19px (or twice that for retina).
120 |
121 | ## Ports
122 |
123 | - Ubuntu Unity [limpbrains/somebar](https://github.com/limpbrains/somebar)
124 |
125 | ## Changelog
126 |
127 | ### 0.1.3
128 |
129 | - AppleScript support (PR #8, thx [Oleg Kertanov](https://github.com/okertanov))
130 |
131 | ### 0.1.2
132 |
133 | - Dark mode support. In dark mode AnyBar will first check for `_alt@2x.png` or `_alt.png` image first, then falls back to `.png`
134 | - Support for Mavericks actually works
135 |
136 | ### 0.1.1
137 |
138 | - Support for Mavericks (PR #2, thx [Oleg Kertanov](https://github.com/okertanov))
139 | - Support for custom images via ~/.AnyBar (PR #1, thx [Paul Boschmann](https://github.com/pboschmann))
140 |
141 | ## License
142 |
143 | Copyright © 2015 Nikita Prokopov
144 |
145 | Licensed under Eclipse Public License (see [LICENSE](LICENSE)).
146 |
147 |
--------------------------------------------------------------------------------
/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(strong, nonatomic) NSString *textTitle;
18 | @property(assign, nonatomic) BOOL dark;
19 | @property(assign, nonatomic) int udpPort;
20 |
21 | @end
22 |
23 | @implementation AppDelegate
24 |
25 | - (void)applicationDidFinishLaunching:(NSNotification *)aNotification
26 | {
27 | _udpPort = -1;
28 | _imageName = @"none";
29 | _textTitle = @" ";
30 | self.statusItem = [self initializeStatusBarItem];
31 | [self refreshDarkMode];
32 |
33 | @try
34 | {
35 | _udpPort = [self getUdpPort];
36 | _udpSocket = [self initializeUdpSocket:_udpPort];
37 | }
38 | @catch (NSException *ex)
39 | {
40 | NSLog(@"Error: %@: %@", ex.name, ex.reason);
41 | _statusItem.image = [NSImage imageNamed:@"exclamation@2x.png"];
42 | }
43 | @finally
44 | {
45 | NSString *portTitle = [NSString stringWithFormat:@"UDP port: %@",
46 | _udpPort >= 0 ? [NSNumber numberWithInt:_udpPort] : @"unavailable"];
47 | NSString *quitTitle = @"Quit";
48 | _statusItem.menu = [self initializeStatusBarMenu:@{
49 | portTitle : [NSValue valueWithPointer:nil],
50 | quitTitle : [NSValue valueWithPointer:@selector(terminate:)]
51 | }];
52 | }
53 |
54 | NSDistributedNotificationCenter *center = [NSDistributedNotificationCenter defaultCenter];
55 | [center addObserver:self
56 | selector:@selector(refreshDarkMode)
57 | name:@"AppleInterfaceThemeChangedNotification"
58 | object:nil];
59 | }
60 |
61 | - (void)applicationWillTerminate:(NSNotification *)aNotification
62 | {
63 | [self shutdownUdpSocket:_udpSocket];
64 | _udpSocket = nil;
65 |
66 | [[NSStatusBar systemStatusBar] removeStatusItem:_statusItem];
67 | _statusItem = nil;
68 | }
69 |
70 | - (int)getUdpPort
71 | {
72 | int port = [self readIntFromEnvironmentVariable:@"ANYBAR_PORT" usingDefault:@"1738"];
73 |
74 | if (port < 0 || port > 65535)
75 | {
76 | @throw([NSException exceptionWithName:@"Argument Exception"
77 | reason:[NSString stringWithFormat:@"UDP Port range is invalid: %d", port]
78 | userInfo:@{ @"argument" : [NSNumber numberWithInt:port] }]);
79 | }
80 |
81 | return port;
82 | }
83 |
84 | - (void)refreshDarkMode
85 | {
86 | NSString *osxMode = [[NSUserDefaults standardUserDefaults] stringForKey:@"AppleInterfaceStyle"];
87 | if ([osxMode isEqualToString:@"Dark"])
88 | self.dark = YES;
89 | else
90 | self.dark = NO;
91 | [self setImage:_imageName];
92 | }
93 |
94 | - (GCDAsyncUdpSocket *)initializeUdpSocket:(int)port
95 | {
96 | NSError *error = nil;
97 | GCDAsyncUdpSocket *udpSocket = [[GCDAsyncUdpSocket alloc]
98 | initWithDelegate:self
99 | delegateQueue:dispatch_get_main_queue()];
100 |
101 | [udpSocket bindToPort:port error:&error];
102 | if (error)
103 | {
104 | @throw([NSException exceptionWithName:@"UDP Exception"
105 | reason:[NSString stringWithFormat:@"Binding to %d failed", port]
106 | userInfo:@{ @"error" : error }]);
107 | }
108 |
109 | [udpSocket beginReceiving:&error];
110 | if (error)
111 | {
112 | @throw([NSException exceptionWithName:@"UDP Exception"
113 | reason:[NSString stringWithFormat:@"Receiving from %d failed", port]
114 | userInfo:@{ @"error" : error }]);
115 | }
116 |
117 | return udpSocket;
118 | }
119 |
120 | - (void)shutdownUdpSocket:(GCDAsyncUdpSocket *)sock
121 | {
122 | if (sock != nil)
123 | {
124 | [sock close];
125 | }
126 | }
127 |
128 | - (void)udpSocket:(GCDAsyncUdpSocket *)sock didReceiveData:(NSData *)data
129 | fromAddress:(NSData *)address
130 | withFilterContext:(id)filterContext
131 | {
132 | [self processUdpSocketMsg:sock withData:data fromAddress:address];
133 | }
134 |
135 | - (NSImage *)tryImage:(NSString *)path
136 | {
137 | NSFileManager *fileManager = [NSFileManager defaultManager];
138 | if ([fileManager fileExistsAtPath:path])
139 | return [[NSImage alloc] initWithContentsOfFile:path];
140 | else
141 | return nil;
142 | }
143 |
144 | - (NSString *)bundledImagePath:(NSString *)name
145 | {
146 | return [[NSBundle mainBundle] pathForResource:name ofType:@"png"];
147 | }
148 |
149 | - (NSString *)homedirImagePath:(NSString *)name
150 | {
151 | return [NSString stringWithFormat:@"%@/%@/%@.png", NSHomeDirectory(), @".AnyBar", name];
152 | }
153 |
154 | - (NSAttributedString *)createAttributedString:(NSString *)string
155 | {
156 | NSFont *stringFont = [NSFont fontWithName:@"Helvetica" size:12.0];
157 |
158 | NSDictionary *stringAttributes =
159 | [NSDictionary dictionaryWithObject:stringFont forKey:NSFontAttributeName];
160 |
161 | NSMutableAttributedString *attributedString =
162 | [[NSMutableAttributedString alloc] initWithString:string
163 | attributes:stringAttributes];
164 | return attributedString;
165 | }
166 |
167 | - (void)setText:(NSString *)title
168 | {
169 | // if (_dark) {
170 | //
171 | // }
172 | _statusItem.attributedTitle = [self createAttributedString:title];
173 | _textTitle = title;
174 | }
175 |
176 | - (BOOL)setImage:(NSString *)name
177 | {
178 |
179 | NSImage *image = nil;
180 | if ([name isEqualToString:@"none"] || [name isEqualToString:@"hide"])
181 | {
182 | _statusItem.alternateImage = nil;
183 | _statusItem.image = nil;
184 | _imageName = nil;
185 | [_statusItem.view setNeedsDisplay:YES];
186 | [_statusItem.view setNeedsLayout:YES];
187 | return YES;
188 | }
189 | if (_dark)
190 | image = [self tryImage:[self bundledImagePath:[name stringByAppendingString:@"_alt@2x"]]];
191 | if (!image)
192 | image = [self tryImage:[self bundledImagePath:[name stringByAppendingString:@"@2x"]]];
193 | if (_dark && !image)
194 | image = [self tryImage:[self homedirImagePath:[name stringByAppendingString:@"_alt"]]];
195 | if (_dark && !image)
196 | image = [self tryImage:[self homedirImagePath:[name stringByAppendingString:@"_alt@2x"]]];
197 | if (!image)
198 | image = [self tryImage:[self homedirImagePath:[name stringByAppendingString:@"@2x"]]];
199 | if (!image)
200 | image = [self tryImage:[self homedirImagePath:name]];
201 | if (!image)
202 | {
203 | return NO;
204 | // if (_dark)
205 | // image = [self tryImage:[self bundledImagePath:@"question_alt@2x"]];
206 | // else
207 | // image = [self tryImage:[self bundledImagePath:@"question@2x"]];
208 | // NSLog(@"Cannot find image '%@'", name);
209 | }
210 | _statusItem.image = image;
211 | _imageName = name;
212 | _statusItem.attributedTitle = [self createAttributedString:_textTitle];
213 | return YES;
214 | }
215 |
216 | - (void)processUdpSocketMsg:(GCDAsyncUdpSocket *)sock withData:(NSData *)data
217 | fromAddress:(NSData *)address
218 | {
219 | NSString *msg = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
220 |
221 | if ([msg isEqualToString:@"quit"])
222 | [[NSApplication sharedApplication] terminate:nil];
223 | else
224 | {
225 | NSArray *stringArray = [msg componentsSeparatedByString:@" "];
226 | if ([self setImage:stringArray[0]])
227 | stringArray = [stringArray subarrayWithRange:NSMakeRange(1, stringArray.count - 1)];
228 | if (stringArray.count > 1)
229 | {
230 | [self setText:[stringArray componentsJoinedByString:@" "]];
231 | }
232 | }
233 | }
234 |
235 | - (NSStatusItem *)initializeStatusBarItem
236 | {
237 | NSStatusItem *statusItem = [[NSStatusBar systemStatusBar] statusItemWithLength:NSVariableStatusItemLength];
238 | statusItem.alternateImage = [NSImage imageNamed:@"black_alt@2x.png"];
239 | statusItem.attributedTitle = [self createAttributedString:@" "];
240 | statusItem.highlightMode = YES;
241 | return statusItem;
242 | }
243 |
244 | - (NSMenu *)initializeStatusBarMenu:(NSDictionary *)menuDictionary
245 | {
246 | NSMenu *menu = [[NSMenu alloc] init];
247 |
248 | [menuDictionary enumerateKeysAndObjectsUsingBlock:^(NSString *key, NSValue *val, BOOL *stop) {
249 | SEL action = nil;
250 | [val getValue:&action];
251 | [menu addItemWithTitle:key action:action keyEquivalent:@""];
252 | }];
253 |
254 | return menu;
255 | }
256 |
257 | - (int)readIntFromEnvironmentVariable:(NSString *)envVariable usingDefault:(NSString *)defStr
258 | {
259 | int intVal = -1;
260 |
261 | NSString *envStr = [[[NSProcessInfo processInfo] environment] objectForKey:envVariable];
262 | if (!envStr)
263 | {
264 | envStr = defStr;
265 | }
266 |
267 | NSNumberFormatter *nFormatter = [[NSNumberFormatter alloc] init];
268 | nFormatter.numberStyle = NSNumberFormatterDecimalStyle;
269 | NSNumber *number = [nFormatter numberFromString:envStr];
270 |
271 | if (!number)
272 | {
273 | @throw([NSException exceptionWithName:@"Argument Exception"
274 | reason:[NSString stringWithFormat:@"Parsing integer from %@ failed", envStr]
275 | userInfo:@{ @"argument" : envStr }]);
276 | }
277 |
278 | intVal = [number intValue];
279 |
280 | return intVal;
281 | }
282 |
283 | - (id)osaImageBridge
284 | {
285 | NSLog(@"OSA Event: %@ - %@", NSStringFromSelector(_cmd), _imageName);
286 |
287 | return _imageName;
288 | }
289 |
290 | - (void)setOsaImageBridge:(id)imgName
291 | {
292 | NSLog(@"OSA Event: %@ - %@", NSStringFromSelector(_cmd), imgName);
293 |
294 | _imageName = (NSString *)imgName;
295 |
296 | [self setImage:_imageName];
297 | }
298 |
299 | - (id)osaTextBridge
300 | {
301 | NSLog(@"OSA Event: %@ - %@", NSStringFromSelector(_cmd), _imageName);
302 |
303 | return _textTitle;
304 | }
305 |
306 | - (void)setOsaTextBridge:(id)textTitle
307 | {
308 | NSLog(@"OSA Event: %@ - %@", NSStringFromSelector(_cmd), textTitle);
309 |
310 | _textTitle = (NSString *)textTitle;
311 |
312 | [self setText:_textTitle];
313 | [_statusItem.view setNeedsDisplay:YES];
314 | [_statusItem.view setNeedsLayout:YES];
315 | }
316 |
317 | @end
318 |
--------------------------------------------------------------------------------
/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 | C5AB32BF1A8F9091002258B6 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = C5AB32BE1A8F9091002258B6 /* AppDelegate.m */; };
14 | C5AB32C11A8F9091002258B6 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = C5AB32C01A8F9091002258B6 /* main.m */; };
15 | C5AB32C31A8F9091002258B6 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = C5AB32C21A8F9091002258B6 /* Images.xcassets */; };
16 | C5AB32E71A8F9B4E002258B6 /* GCDAsyncSocket.m in Sources */ = {isa = PBXBuildFile; fileRef = C5AB32E41A8F9B4E002258B6 /* GCDAsyncSocket.m */; };
17 | C5AB32E81A8F9B4E002258B6 /* GCDAsyncUdpSocket.m in Sources */ = {isa = PBXBuildFile; fileRef = C5AB32E61A8F9B4E002258B6 /* GCDAsyncUdpSocket.m */; };
18 | C5E0271D1AA6435E0032F2E9 /* black_alt@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = C5E027101AA6435E0032F2E9 /* black_alt@2x.png */; };
19 | C5E0271E1AA6435E0032F2E9 /* black@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = C5E027111AA6435E0032F2E9 /* black@2x.png */; };
20 | C5E0271F1AA6435E0032F2E9 /* blue@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = C5E027121AA6435E0032F2E9 /* blue@2x.png */; };
21 | C5E027201AA6435E0032F2E9 /* cyan@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = C5E027131AA6435E0032F2E9 /* cyan@2x.png */; };
22 | C5E027211AA6435E0032F2E9 /* green@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = C5E027141AA6435E0032F2E9 /* green@2x.png */; };
23 | C5E027221AA6435E0032F2E9 /* orange@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = C5E027151AA6435E0032F2E9 /* orange@2x.png */; };
24 | C5E027231AA6435E0032F2E9 /* purple@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = C5E027161AA6435E0032F2E9 /* purple@2x.png */; };
25 | C5E027241AA6435E0032F2E9 /* red@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = C5E027171AA6435E0032F2E9 /* red@2x.png */; };
26 | C5E027271AA6435E0032F2E9 /* white_alt@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = C5E0271A1AA6435E0032F2E9 /* white_alt@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 | C5E027301AA64BD90032F2E9 /* question_alt@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = C5E0272D1AA64BD90032F2E9 /* question_alt@2x.png */; };
31 | C5E027311AA64BD90032F2E9 /* question@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = C5E0272E1AA64BD90032F2E9 /* question@2x.png */; };
32 | /* End PBXBuildFile section */
33 |
34 | /* Begin PBXFileReference section */
35 | C03A3D3D1AA78DAD0030B668 /* AnyBar.sdef */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = AnyBar.sdef; sourceTree = ""; };
36 | C03A3D411AA7A6540030B668 /* AnyBarApp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AnyBarApp.h; sourceTree = ""; };
37 | C03A3D421AA7A6540030B668 /* AnyBarApp.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AnyBarApp.m; sourceTree = ""; };
38 | C511DFFB1AA4E9CF00DEE15F /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; };
39 | C5AB32B81A8F9091002258B6 /* AnyBar.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = AnyBar.app; sourceTree = BUILT_PRODUCTS_DIR; };
40 | C5AB32BC1A8F9091002258B6 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
41 | C5AB32BD1A8F9091002258B6 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; };
42 | C5AB32BE1A8F9091002258B6 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; };
43 | C5AB32C01A8F9091002258B6 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; };
44 | C5AB32C21A8F9091002258B6 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; };
45 | C5AB32C51A8F9091002258B6 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; };
46 | C5AB32E31A8F9B4E002258B6 /* GCDAsyncSocket.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GCDAsyncSocket.h; sourceTree = ""; };
47 | C5AB32E41A8F9B4E002258B6 /* GCDAsyncSocket.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GCDAsyncSocket.m; sourceTree = ""; };
48 | C5AB32E51A8F9B4E002258B6 /* GCDAsyncUdpSocket.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GCDAsyncUdpSocket.h; sourceTree = ""; };
49 | C5AB32E61A8F9B4E002258B6 /* GCDAsyncUdpSocket.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GCDAsyncUdpSocket.m; sourceTree = ""; };
50 | C5E027101AA6435E0032F2E9 /* black_alt@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "black_alt@2x.png"; 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 | C5E0271A1AA6435E0032F2E9 /* white_alt@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "white_alt@2x.png"; sourceTree = ""; };
59 | C5E0271B1AA6435E0032F2E9 /* white@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "white@2x.png"; sourceTree = ""; };
60 | C5E0271C1AA6435E0032F2E9 /* yellow@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "yellow@2x.png"; sourceTree = ""; };
61 | C5E0272C1AA64BD90032F2E9 /* exclamation@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "exclamation@2x.png"; sourceTree = ""; };
62 | C5E0272D1AA64BD90032F2E9 /* question_alt@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "question_alt@2x.png"; sourceTree = ""; };
63 | C5E0272E1AA64BD90032F2E9 /* question@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "question@2x.png"; sourceTree = ""; };
64 | /* End PBXFileReference section */
65 |
66 | /* Begin PBXFrameworksBuildPhase section */
67 | C5AB32B51A8F9091002258B6 /* Frameworks */ = {
68 | isa = PBXFrameworksBuildPhase;
69 | buildActionMask = 2147483647;
70 | files = (
71 | );
72 | runOnlyForDeploymentPostprocessing = 0;
73 | };
74 | /* End PBXFrameworksBuildPhase section */
75 |
76 | /* Begin PBXGroup section */
77 | 7648BAAC1AA5A3C0003DA28F /* Resources */ = {
78 | isa = PBXGroup;
79 | children = (
80 | C5E0272C1AA64BD90032F2E9 /* exclamation@2x.png */,
81 | C5E0272D1AA64BD90032F2E9 /* question_alt@2x.png */,
82 | C5E0272E1AA64BD90032F2E9 /* question@2x.png */,
83 | C5E027101AA6435E0032F2E9 /* black_alt@2x.png */,
84 | C5E027111AA6435E0032F2E9 /* black@2x.png */,
85 | C5E027121AA6435E0032F2E9 /* blue@2x.png */,
86 | C5E027131AA6435E0032F2E9 /* cyan@2x.png */,
87 | C5E027141AA6435E0032F2E9 /* green@2x.png */,
88 | C5E027151AA6435E0032F2E9 /* orange@2x.png */,
89 | C5E027161AA6435E0032F2E9 /* purple@2x.png */,
90 | C5E027171AA6435E0032F2E9 /* red@2x.png */,
91 | C5E0271A1AA6435E0032F2E9 /* white_alt@2x.png */,
92 | C5E0271B1AA6435E0032F2E9 /* white@2x.png */,
93 | C5E0271C1AA6435E0032F2E9 /* yellow@2x.png */,
94 | );
95 | path = Resources;
96 | sourceTree = "";
97 | };
98 | C5AB32AF1A8F9091002258B6 = {
99 | isa = PBXGroup;
100 | children = (
101 | C5AB32BA1A8F9091002258B6 /* AnyBar */,
102 | C5AB32B91A8F9091002258B6 /* Products */,
103 | C511DFFB1AA4E9CF00DEE15F /* README.md */,
104 | );
105 | sourceTree = "";
106 | };
107 | C5AB32B91A8F9091002258B6 /* Products */ = {
108 | isa = PBXGroup;
109 | children = (
110 | C5AB32B81A8F9091002258B6 /* AnyBar.app */,
111 | );
112 | name = Products;
113 | sourceTree = "";
114 | };
115 | C5AB32BA1A8F9091002258B6 /* AnyBar */ = {
116 | isa = PBXGroup;
117 | children = (
118 | C5AB32E31A8F9B4E002258B6 /* GCDAsyncSocket.h */,
119 | C5AB32E41A8F9B4E002258B6 /* GCDAsyncSocket.m */,
120 | C5AB32E51A8F9B4E002258B6 /* GCDAsyncUdpSocket.h */,
121 | C5AB32E61A8F9B4E002258B6 /* GCDAsyncUdpSocket.m */,
122 | C5AB32BD1A8F9091002258B6 /* AppDelegate.h */,
123 | C5AB32BE1A8F9091002258B6 /* AppDelegate.m */,
124 | C03A3D411AA7A6540030B668 /* AnyBarApp.h */,
125 | C03A3D421AA7A6540030B668 /* AnyBarApp.m */,
126 | C5AB32C21A8F9091002258B6 /* Images.xcassets */,
127 | C5AB32C41A8F9091002258B6 /* MainMenu.xib */,
128 | 7648BAAC1AA5A3C0003DA28F /* Resources */,
129 | C5AB32BB1A8F9091002258B6 /* Supporting Files */,
130 | );
131 | path = AnyBar;
132 | sourceTree = "";
133 | };
134 | C5AB32BB1A8F9091002258B6 /* Supporting Files */ = {
135 | isa = PBXGroup;
136 | children = (
137 | C03A3D3D1AA78DAD0030B668 /* AnyBar.sdef */,
138 | C5AB32BC1A8F9091002258B6 /* Info.plist */,
139 | C5AB32C01A8F9091002258B6 /* main.m */,
140 | );
141 | name = "Supporting Files";
142 | sourceTree = "";
143 | };
144 | /* End PBXGroup section */
145 |
146 | /* Begin PBXNativeTarget section */
147 | C5AB32B71A8F9091002258B6 /* AnyBar */ = {
148 | isa = PBXNativeTarget;
149 | buildConfigurationList = C5AB32D51A8F9091002258B6 /* Build configuration list for PBXNativeTarget "AnyBar" */;
150 | buildPhases = (
151 | C5AB32B41A8F9091002258B6 /* Sources */,
152 | C5AB32B51A8F9091002258B6 /* Frameworks */,
153 | C5AB32B61A8F9091002258B6 /* Resources */,
154 | );
155 | buildRules = (
156 | );
157 | dependencies = (
158 | );
159 | name = AnyBar;
160 | productName = AnyBar;
161 | productReference = C5AB32B81A8F9091002258B6 /* AnyBar.app */;
162 | productType = "com.apple.product-type.application";
163 | };
164 | /* End PBXNativeTarget section */
165 |
166 | /* Begin PBXProject section */
167 | C5AB32B01A8F9091002258B6 /* Project object */ = {
168 | isa = PBXProject;
169 | attributes = {
170 | LastUpgradeCheck = 0610;
171 | ORGANIZATIONNAME = "Nikita Prokopov";
172 | TargetAttributes = {
173 | C5AB32B71A8F9091002258B6 = {
174 | CreatedOnToolsVersion = 6.1.1;
175 | };
176 | };
177 | };
178 | buildConfigurationList = C5AB32B31A8F9091002258B6 /* Build configuration list for PBXProject "AnyBar" */;
179 | compatibilityVersion = "Xcode 3.2";
180 | developmentRegion = English;
181 | hasScannedForEncodings = 0;
182 | knownRegions = (
183 | en,
184 | Base,
185 | );
186 | mainGroup = C5AB32AF1A8F9091002258B6;
187 | productRefGroup = C5AB32B91A8F9091002258B6 /* Products */;
188 | projectDirPath = "";
189 | projectRoot = "";
190 | targets = (
191 | C5AB32B71A8F9091002258B6 /* AnyBar */,
192 | );
193 | };
194 | /* End PBXProject section */
195 |
196 | /* Begin PBXResourcesBuildPhase section */
197 | C5AB32B61A8F9091002258B6 /* Resources */ = {
198 | isa = PBXResourcesBuildPhase;
199 | buildActionMask = 2147483647;
200 | files = (
201 | C5E027241AA6435E0032F2E9 /* red@2x.png in Resources */,
202 | C5E027231AA6435E0032F2E9 /* purple@2x.png in Resources */,
203 | C5AB32C31A8F9091002258B6 /* Images.xcassets in Resources */,
204 | C5E027291AA6435E0032F2E9 /* yellow@2x.png in Resources */,
205 | C5E027311AA64BD90032F2E9 /* question@2x.png in Resources */,
206 | C5E027301AA64BD90032F2E9 /* question_alt@2x.png in Resources */,
207 | C5E027271AA6435E0032F2E9 /* white_alt@2x.png in Resources */,
208 | C5E027281AA6435E0032F2E9 /* white@2x.png in Resources */,
209 | 7648BAC31AA5A50B003DA28F /* MainMenu.xib in Resources */,
210 | C5E027211AA6435E0032F2E9 /* green@2x.png in Resources */,
211 | C5E0272F1AA64BD90032F2E9 /* exclamation@2x.png in Resources */,
212 | C5E0271E1AA6435E0032F2E9 /* black@2x.png in Resources */,
213 | C5E027201AA6435E0032F2E9 /* cyan@2x.png in Resources */,
214 | C5E0271F1AA6435E0032F2E9 /* blue@2x.png in Resources */,
215 | C5E027221AA6435E0032F2E9 /* orange@2x.png in Resources */,
216 | C03A3D3E1AA78DAD0030B668 /* AnyBar.sdef in Resources */,
217 | C5E0271D1AA6435E0032F2E9 /* black_alt@2x.png in Resources */,
218 | );
219 | runOnlyForDeploymentPostprocessing = 0;
220 | };
221 | /* End PBXResourcesBuildPhase section */
222 |
223 | /* Begin PBXSourcesBuildPhase section */
224 | C5AB32B41A8F9091002258B6 /* Sources */ = {
225 | isa = PBXSourcesBuildPhase;
226 | buildActionMask = 2147483647;
227 | files = (
228 | C03A3D431AA7A6540030B668 /* AnyBarApp.m in Sources */,
229 | C5AB32E81A8F9B4E002258B6 /* GCDAsyncUdpSocket.m in Sources */,
230 | C5AB32E71A8F9B4E002258B6 /* GCDAsyncSocket.m in Sources */,
231 | C5AB32C11A8F9091002258B6 /* main.m in Sources */,
232 | C5AB32BF1A8F9091002258B6 /* AppDelegate.m in Sources */,
233 | );
234 | runOnlyForDeploymentPostprocessing = 0;
235 | };
236 | /* End PBXSourcesBuildPhase section */
237 |
238 | /* Begin PBXVariantGroup section */
239 | C5AB32C41A8F9091002258B6 /* MainMenu.xib */ = {
240 | isa = PBXVariantGroup;
241 | children = (
242 | C5AB32C51A8F9091002258B6 /* Base */,
243 | );
244 | name = MainMenu.xib;
245 | sourceTree = "";
246 | };
247 | /* End PBXVariantGroup section */
248 |
249 | /* Begin XCBuildConfiguration section */
250 | C5AB32D31A8F9091002258B6 /* Debug */ = {
251 | isa = XCBuildConfiguration;
252 | buildSettings = {
253 | ALWAYS_SEARCH_USER_PATHS = NO;
254 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
255 | CLANG_CXX_LIBRARY = "libc++";
256 | CLANG_ENABLE_MODULES = YES;
257 | CLANG_ENABLE_OBJC_ARC = YES;
258 | CLANG_WARN_BOOL_CONVERSION = YES;
259 | CLANG_WARN_CONSTANT_CONVERSION = YES;
260 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
261 | CLANG_WARN_EMPTY_BODY = YES;
262 | CLANG_WARN_ENUM_CONVERSION = YES;
263 | CLANG_WARN_INT_CONVERSION = YES;
264 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
265 | CLANG_WARN_UNREACHABLE_CODE = YES;
266 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
267 | CODE_SIGN_IDENTITY = "-";
268 | COPY_PHASE_STRIP = NO;
269 | ENABLE_STRICT_OBJC_MSGSEND = YES;
270 | GCC_C_LANGUAGE_STANDARD = gnu99;
271 | GCC_DYNAMIC_NO_PIC = NO;
272 | GCC_OPTIMIZATION_LEVEL = 0;
273 | GCC_PREPROCESSOR_DEFINITIONS = (
274 | "DEBUG=1",
275 | "$(inherited)",
276 | );
277 | GCC_SYMBOLS_PRIVATE_EXTERN = NO;
278 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
279 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
280 | GCC_WARN_UNDECLARED_SELECTOR = YES;
281 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
282 | GCC_WARN_UNUSED_FUNCTION = YES;
283 | GCC_WARN_UNUSED_VARIABLE = YES;
284 | MACOSX_DEPLOYMENT_TARGET = 10.9;
285 | MTL_ENABLE_DEBUG_INFO = YES;
286 | ONLY_ACTIVE_ARCH = YES;
287 | SDKROOT = macosx10.9;
288 | };
289 | name = Debug;
290 | };
291 | C5AB32D41A8F9091002258B6 /* Release */ = {
292 | isa = XCBuildConfiguration;
293 | buildSettings = {
294 | ALWAYS_SEARCH_USER_PATHS = NO;
295 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
296 | CLANG_CXX_LIBRARY = "libc++";
297 | CLANG_ENABLE_MODULES = YES;
298 | CLANG_ENABLE_OBJC_ARC = YES;
299 | CLANG_WARN_BOOL_CONVERSION = YES;
300 | CLANG_WARN_CONSTANT_CONVERSION = YES;
301 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
302 | CLANG_WARN_EMPTY_BODY = YES;
303 | CLANG_WARN_ENUM_CONVERSION = YES;
304 | CLANG_WARN_INT_CONVERSION = YES;
305 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
306 | CLANG_WARN_UNREACHABLE_CODE = YES;
307 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
308 | CODE_SIGN_IDENTITY = "-";
309 | COPY_PHASE_STRIP = YES;
310 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
311 | ENABLE_NS_ASSERTIONS = NO;
312 | ENABLE_STRICT_OBJC_MSGSEND = YES;
313 | GCC_C_LANGUAGE_STANDARD = gnu99;
314 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
315 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
316 | GCC_WARN_UNDECLARED_SELECTOR = YES;
317 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
318 | GCC_WARN_UNUSED_FUNCTION = YES;
319 | GCC_WARN_UNUSED_VARIABLE = YES;
320 | MACOSX_DEPLOYMENT_TARGET = 10.9;
321 | MTL_ENABLE_DEBUG_INFO = NO;
322 | SDKROOT = macosx10.9;
323 | };
324 | name = Release;
325 | };
326 | C5AB32D61A8F9091002258B6 /* Debug */ = {
327 | isa = XCBuildConfiguration;
328 | buildSettings = {
329 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
330 | COMBINE_HIDPI_IMAGES = YES;
331 | INFOPLIST_FILE = AnyBar/Info.plist;
332 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks";
333 | MACOSX_DEPLOYMENT_TARGET = 10.9;
334 | PRODUCT_NAME = "$(TARGET_NAME)";
335 | };
336 | name = Debug;
337 | };
338 | C5AB32D71A8F9091002258B6 /* Release */ = {
339 | isa = XCBuildConfiguration;
340 | buildSettings = {
341 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
342 | COMBINE_HIDPI_IMAGES = YES;
343 | INFOPLIST_FILE = AnyBar/Info.plist;
344 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks";
345 | MACOSX_DEPLOYMENT_TARGET = 10.9;
346 | PRODUCT_NAME = "$(TARGET_NAME)";
347 | };
348 | name = Release;
349 | };
350 | /* End XCBuildConfiguration section */
351 |
352 | /* Begin XCConfigurationList section */
353 | C5AB32B31A8F9091002258B6 /* Build configuration list for PBXProject "AnyBar" */ = {
354 | isa = XCConfigurationList;
355 | buildConfigurations = (
356 | C5AB32D31A8F9091002258B6 /* Debug */,
357 | C5AB32D41A8F9091002258B6 /* Release */,
358 | );
359 | defaultConfigurationIsVisible = 0;
360 | defaultConfigurationName = Release;
361 | };
362 | C5AB32D51A8F9091002258B6 /* Build configuration list for PBXNativeTarget "AnyBar" */ = {
363 | isa = XCConfigurationList;
364 | buildConfigurations = (
365 | C5AB32D61A8F9091002258B6 /* Debug */,
366 | C5AB32D71A8F9091002258B6 /* Release */,
367 | );
368 | defaultConfigurationIsVisible = 0;
369 | defaultConfigurationName = Release;
370 | };
371 | /* End XCConfigurationList section */
372 | };
373 | rootObject = C5AB32B01A8F9091002258B6 /* Project object */;
374 | }
375 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------