More work done to networking. Bugfixes out the wazoo, but there's still
[MenuTunes.git] / NetworkController.m
1 /*
2  *      MenuTunes
3  *  NetworkController
4  *    Rendezvous network controller
5  *
6  *  Original Author : Kent Sutherland <ksuther@ithinksw.com>
7  *   Responsibility : Kent Sutherland <ksuther@ithinksw.com>
8  *
9  *  Copyright (c) 2003 iThink Software.
10  *  All Rights Reserved
11  *
12  */
13
14 #import "NetworkController.h"
15 #import "MainController.h"
16 #import "NetworkObject.h"
17 #import <ITFoundation/ITDebug.h>
18 #import <ITFoundation/ITFoundation.h>
19
20 static NetworkController *sharedController;
21
22 @implementation NetworkController
23
24 + (NetworkController *)sharedController
25 {
26     return sharedController;
27 }
28
29 - (id)init
30 {
31     if ( (self = [super init]) ) {
32         sharedController = self;
33         browser = [[NSNetServiceBrowser alloc] init];
34         [browser setDelegate:self];
35     }
36     return self;
37 }
38
39 - (void)dealloc
40 {
41     [self disconnect];
42     if (serverOn) {
43         [serverConnection release];
44     }
45     [serverPass release];
46     [clientPass release];
47     [clientProxy release];
48     [remoteServices release];
49     [browser release];
50     [service stop];
51     [service release];
52     [super dealloc];
53 }
54
55 - (void)startRemoteServerSearch
56 {
57     [browser searchForServicesOfType:@"_mttp._tcp." inDomain:@""];
58     [remoteServices release];
59     remoteServices = [[NSMutableArray alloc] init];
60 }
61
62 - (void)stopRemoteServerSearch
63 {
64     [browser stop];
65 }
66
67 - (void)setServerStatus:(BOOL)status
68 {
69     if (!serverOn && status) {
70         NSString *name = [[NSUserDefaults standardUserDefaults] stringForKey:@"sharedPlayerName"];
71         unsigned char buffer;
72         NSData *fullPass;
73         //Turn on
74         NS_DURING
75             serverPort = [[NSSocketPort alloc] initWithTCPPort:SERVER_PORT];
76             serverConnection = [[NSConnection alloc] initWithReceivePort:serverPort
77                                                      sendPort:serverPort];
78             [serverConnection setRootObject:[[NetworkObject alloc] init]];
79             [serverConnection registerName:@"ITMTPlayerHost"];
80         NS_HANDLER
81             [[serverConnection rootObject] release];
82             [serverConnection release];
83             [serverPort release];
84             ITDebugLog(@"Error starting server!");
85         NS_ENDHANDLER
86         ITDebugLog(@"Started server.");
87         if (!name) {
88             name = @"MenuTunes Shared Player";
89         }
90         service = [[NSNetService alloc] initWithDomain:@""
91                                         type:@"_mttp._tcp."
92                                         name:name
93                                         port:SERVER_PORT];
94         fullPass = [[NSUserDefaults standardUserDefaults] dataForKey:@"sharedPlayerPassword"];
95         if (fullPass) {
96             [fullPass getBytes:&buffer range:NSMakeRange(6, 4)];
97             [serverPass release];
98             serverPass = [[NSData alloc] initWithBytes:&buffer length:strlen(&buffer)];
99         } else {
100             serverPass = nil;
101         }
102         [service publish];
103         serverOn = YES;
104     } else if (serverOn && !status && [serverConnection isValid]) {
105         //Turn off
106         [service stop];
107         [serverConnection registerName:nil];
108         [[serverConnection rootObject] release];
109         [serverConnection release];
110         ITDebugLog(@"Stopped server.");
111         serverOn = NO;
112     }
113 }
114
115 - (int)connectToHost:(NSString *)host
116 {
117     NSData *fullPass = [[NSUserDefaults standardUserDefaults] dataForKey:@"connectPassword"];
118     unsigned char buffer;
119     ITDebugLog(@"Connecting to host: %@", host);
120     [remoteHost release];
121     remoteHost = [host copy];
122     if (fullPass) {
123         [fullPass getBytes:&buffer range:NSMakeRange(6, 4)];
124         [clientPass release];
125         clientPass = [[NSData alloc] initWithBytes:&buffer length:strlen(&buffer)];
126     } else {
127         clientPass = nil;
128     }
129     NS_DURING
130         clientPort = [[NSSocketPort alloc] initRemoteWithTCPPort:SERVER_PORT
131                                            host:host];
132         clientConnection = [[NSConnection connectionWithReceivePort:nil sendPort:clientPort] retain];
133         [clientConnection setReplyTimeout:5];
134         clientProxy = [[clientConnection rootProxy] retain];
135     NS_HANDLER
136         [clientConnection release];
137         [clientPort release];
138         ITDebugLog(@"Connection to host failed: %@", host);
139         return NO;
140     NS_ENDHANDLER
141     
142     if (!clientProxy) {
143         ITDebugLog(@"Null proxy! Couldn't connect!");
144         [self disconnect];
145         return NO;
146     }
147     
148     if ([clientProxy requiresPassword]) {
149         ITDebugLog(@"Sending password.");
150         if (![clientProxy sendPassword:[[NSUserDefaults standardUserDefaults] dataForKey:@"connectPassword"]]) {
151             ITDebugLog(@"Invalid password!");
152             [self disconnect];
153             return -1;
154         }
155     }
156     
157     ITDebugLog(@"Connected to host: %@", host);
158     [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(disconnect) name:NSConnectionDidDieNotification object:clientConnection];
159     connectedToServer = 1;
160     return 1;
161 }
162
163 - (BOOL)disconnect
164 {
165     ITDebugLog(@"Disconnecting from host.");
166     connectedToServer = NO;
167     [remoteHost release];
168     remoteHost = nil;
169     [[NSNotificationCenter defaultCenter] removeObserver:self];
170     [clientProxy release];
171     [clientConnection release];
172     return YES;
173 }
174
175 - (BOOL)checkForServerAtHost:(NSString *)host
176 {
177     NSData *fullPass = [[NSUserDefaults standardUserDefaults] dataForKey:@"connectPassword"];
178     unsigned char buffer;
179     NSConnection *testConnection;
180     NSSocketPort *testPort;
181     NetworkObject *tempProxy;
182     ITDebugLog(@"Checking for shared remote at %@.", host);
183     if (fullPass) {
184         [fullPass getBytes:&buffer range:NSMakeRange(6, 4)];
185         [clientPass release];
186         clientPass = [[NSData alloc] initWithBytes:&buffer length:strlen(&buffer)];
187     } else {
188         clientPass = nil;
189     }
190     
191     NS_DURING
192         testPort = [[NSSocketPort alloc] initRemoteWithTCPPort:SERVER_PORT
193                                          host:host];
194         testConnection = [[NSConnection connectionWithReceivePort:nil sendPort:testPort] retain];
195         [testConnection setReplyTimeout:2];
196         tempProxy = (NetworkObject *)[testConnection rootProxy];
197         [tempProxy serverName];
198     NS_HANDLER
199         ITDebugLog(@"Connection to host failed: %@", host);
200         [testConnection release];
201         [testPort release];
202         return NO;
203     NS_ENDHANDLER
204     
205     if (!clientProxy) {
206         ITDebugLog(@"Null proxy! Couldn't connect!");
207         [testConnection release];
208         [testPort release];
209         return NO;
210     }
211     [testConnection release];
212     [testPort release];
213     return YES;
214 }
215
216 - (BOOL)isServerOn
217 {
218     return serverOn;
219 }
220
221 - (BOOL)isClientConnected
222 {
223     return clientConnected;
224 }
225
226 - (BOOL)isConnectedToServer
227 {
228     return connectedToServer;
229 }
230
231 - (NSString *)remoteHost
232 {
233     return remoteHost;
234 }
235
236 - (NetworkObject *)networkObject
237 {
238     return clientProxy;
239 }
240
241 - (NSArray *)remoteServices
242 {
243     return remoteServices;
244 }
245
246 - (void)netServiceBrowser:(NSNetServiceBrowser *)aNetServiceBrowser didFindService:(NSNetService *)aNetService moreComing:(BOOL)moreComing
247 {
248     ITDebugLog(@"Found service named %@.", [aNetService name]);
249     [remoteServices addObject:aNetService];
250     [aNetService setDelegate:self];
251     [aNetService resolve];
252     if (!moreComing) {
253         [[NSNotificationCenter defaultCenter] postNotificationName:@"ITMTFoundNetService" object:nil];
254     }
255 }
256
257 - (void)netServiceBrowser:(NSNetServiceBrowser *)aNetServiceBrowser didRemoveService:(NSNetService*)aNetService moreComing:(BOOL)moreComing
258 {
259     ITDebugLog(@"Removed service named %@.", [aNetService name]);
260     [remoteServices removeObject:aNetService];
261     if (!moreComing) {
262         [[NSNotificationCenter defaultCenter] postNotificationName:@"ITMTFoundNetService" object:nil];
263     }
264 }
265
266 - (void)netServiceDidResolveAddress:(NSNetService *)sender
267 {
268     ITDebugLog(@"Resolved service named %@.", [sender name]);
269     NSLog(@"Resolved service named %@.", [sender name]);
270     [[NSNotificationCenter defaultCenter] postNotificationName:@"ITMTFoundNetService" object:nil];
271     [sender stop];
272 }
273
274 - (void)netServiceWillResolve:(NSNetService *)sender
275 {
276     ITDebugLog(@"Resolving service named %@.", [sender name]);
277 }
278
279 - (void)netService:(NSNetService *)sender didNotResolve:(NSDictionary *)errorDict
280 {
281     ITDebugLog(@"Error resolving service %@.", errorDict);
282 }
283
284 @end