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