-
Notifications
You must be signed in to change notification settings - Fork 41
/
AMSession.m
556 lines (458 loc) · 20.1 KB
/
AMSession.m
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
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
// Copyright (C) 2008 Antoine Mercadal
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#import "AMSession.h"
#import "AMResourcesHelper.h"
@implementation AMSession
@synthesize sessionName;
@synthesize portsMap;
@synthesize remoteHost;
@synthesize statusImagePath;
@synthesize connected;
@synthesize connectionInProgress;
@synthesize currentServer;
@synthesize sessionTunnelType;
@synthesize tunnelTypeImagePath;
@synthesize connectionLink;
@synthesize globalProxyPort;
@synthesize useDynamicProxy;
@synthesize childrens;
@synthesize isLeaf;
@synthesize isGroup;
@synthesize autostart;
@synthesize networkService;
@synthesize autoReconnect;
#pragma mark Initilizations
- (id) init
{
self = [super init];
[self setStatusImagePath:[AMResourcesHelper pathForImageNamed:@"statusRed"]];
[self setConnected:NO];
[self setConnectionInProgress:NO];
[self setSessionTunnelType:AMSessionOutgoingTunnel];
[self setGlobalProxyPort:@"7777"];
[self setUseDynamicProxy:NO];
[self setChildrens:nil];
[self setIsLeaf:YES];
[self setIsGroup:NO];
[self setAutostart:NO];
[self setAutoReconnect:NO];
autoReconnectTimes = 0;
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(listernerForSSHTunnelDown:)
name:@"NSTaskDidTerminateNotification" object:self];
return self;
}
- (void) prepareAuthorization
{
OSStatus myStatus;
AuthorizationFlags myFlags = kAuthorizationFlagDefaults;
AuthorizationRef myAuthorizationRef;
myStatus = AuthorizationCreate(NULL, kAuthorizationEmptyEnvironment,
myFlags, &myAuthorizationRef);
if (myStatus != errAuthorizationSuccess)
{
NSLog(@"An administrator password is required...");
}
else
{
AuthorizationItem myItems = {kAuthorizationRightExecute, 0, NULL, 0};
AuthorizationRights myRights = {1, &myItems};
myFlags = kAuthorizationFlagDefaults |
kAuthorizationFlagInteractionAllowed |
kAuthorizationFlagPreAuthorize |
kAuthorizationFlagExtendRights;
myStatus = AuthorizationCopyRights (myAuthorizationRef, &myRights, NULL, myFlags, NULL );
}
}
- (id) initWithCoder:(NSCoder *)coder
{
self = [super init];
sessionName = [coder decodeObjectForKey:@"MVsessionName"];
portsMap = [coder decodeObjectForKey:@"portsMap"];
remoteHost = [coder decodeObjectForKey:@"MVremoteHost"];
statusImagePath = [coder decodeObjectForKey:@"MVStatusImagePath"];
currentServer = [coder decodeObjectForKey:@"MVcurrentServer"];
globalProxyPort = [coder decodeObjectForKey:@"MVdynamicProxyPort"];
sessionTunnelType = [coder decodeIntForKey:@"MVoutgoingTunnel"];
useDynamicProxy = [coder decodeBoolForKey:@"MVuseDynamicProxy"];
childrens = [coder decodeObjectForKey:@"MVChildrens"];
isLeaf = [coder decodeBoolForKey:@"MVIsLeaf"];
autostart = [coder decodeBoolForKey:@"MVAutostart"];
autoReconnect = [coder decodeBoolForKey:@"MVAutoReconnect"];
isGroup = [coder decodeBoolForKey:@"MVIsGroup"];
networkService = [coder decodeObjectForKey:@"MVNetworkService"];
[self setConnected:NO];
[self setConnectionInProgress:NO];
autoReconnectTimes = 0;
if (![self isGroup])
[self setStatusImagePath:[AMResourcesHelper pathForImageNamed:@"statusRed"]];
else
[self setStatusImagePath:@""];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(listernerForSSHTunnelDown:)
name:@"NSTaskDidTerminateNotification" object:self];
return self;
}
- (void) encodeWithCoder:(NSCoder *) coder
{
[coder encodeObject:sessionName forKey:@"MVsessionName"];
[coder encodeObject:portsMap forKey:@"portsMap"];
[coder encodeObject:remoteHost forKey:@"MVremoteHost"];
[coder encodeObject:statusImagePath forKey:@"MVStatusImagePath"];
[coder encodeObject:currentServer forKey:@"MVcurrentServer"];
[coder encodeInt:sessionTunnelType forKey:@"MVoutgoingTunnel"];
[coder encodeObject:globalProxyPort forKey:@"MVdynamicProxyPort"];
[coder encodeBool:useDynamicProxy forKey:@"MVuseDynamicProxy"];
[coder encodeObject:childrens forKey:@"MVChildrens"];
[coder encodeBool:isLeaf forKey:@"MVIsLeaf"];
[coder encodeBool:autostart forKey:@"MVAutostart"];
[coder encodeBool:autoReconnect forKey:@"MVAutoReconnect"];
[coder encodeBool:isGroup forKey:@"MVIsGroup"];
[coder encodeObject:networkService forKey:@"MVNetworkService"];
}
- (void) dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
sessionName = nil;
portsMap = nil;
remoteHost = nil;
stdOut = nil;
if ([sshTask isRunning] == YES)
[sshTask terminate];
sshTask = nil;
}
#pragma mark Overloaded accesors
- (NSString *) tunnelTypeImagePath
{
if ([self sessionTunnelType] == AMSessionOutgoingTunnel)
return [[NSBundle mainBundle] pathForResource:@"outTunnel" ofType:@"tif"];
else if ([self sessionTunnelType] == AMSessionIncomingTunnel)
return [[NSBundle mainBundle] pathForResource:@"inTunnel" ofType:@"tif"];
else
return [[NSBundle mainBundle] pathForResource:@"inTunnel" ofType:@"tif"];
}
- (void) setSessionTunnelType:(NSInteger)newValue
{
[self willChangeValueForKey:@"outgoingTunnel"];
[self willChangeValueForKey:@"tunnelTypeImagePath"];
[self willChangeValueForKey:@"remoteHost"];
sessionTunnelType = newValue;
[self didChangeValueForKey:@"outgoingTunnel"];
[self didChangeValueForKey:@"tunnelTypeImagePath"];
[self didChangeValueForKey:@"remoteHost"];
}
#pragma mark Helper methods
- (void)setProxyEnableForThisSession:(BOOL)enabled onPort:(NSString*)port
{
NSTask *activateProxy = [[NSTask alloc] init];
[activateProxy setLaunchPath:@"/usr/sbin/networksetup"];
NSLog(@"%@", networkService);
if (enabled)
[activateProxy setArguments:[NSArray arrayWithObjects:@"-setsocksfirewallproxy",
[self networkService],
@"127.0.0.1", port, @"off", nil]];
else
[activateProxy setArguments:[NSArray arrayWithObjects:@"-setsocksfirewallproxystate",
[self networkService]
, @"off", nil]];
//[activateProxy launch];
[activateProxy performSelector:@selector(launch) withObject:nil afterDelay:0.1];
}
- (NSMutableArray *) parsePortsSequence:(NSString*)seq
{
NSArray *units;
NSMutableArray *ranges = [[NSMutableArray alloc] init];
NSMutableArray *ports = [[NSMutableArray alloc] init];
NSPredicate *containRange = [NSPredicate predicateWithFormat:@"SELF contains[c] '-' "];
NSPredicate *validPort = [NSPredicate predicateWithFormat:@"SELF matches '[0-9]+'"];
units = [seq componentsSeparatedByCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@" ,;"]];
for (NSString* s in units)
{
if ([containRange evaluateWithObject:s] == YES)
{
[ranges addObject:s];
}
else if ([validPort evaluateWithObject:s])
{
[ports addObject:s];
}
}
for (NSString* s in ranges)
{
NSInteger startPort;
NSInteger stopPort;
NSInteger i;
NSArray *bounds;
bounds = [s componentsSeparatedByString:@"-"];
startPort = [[bounds objectAtIndex:0] intValue];
stopPort = [[bounds objectAtIndex:1] intValue];
for (i = startPort; i <= stopPort; i++)
[ports addObject:[NSString stringWithFormat:@"%ld", (long)i]];
}
return ports;
}
- (NSMutableString *) prepareSSHCommandWithRemotePorts:(NSMutableArray *)remotePorts localPorts:(NSMutableArray *)localPorts
{
NSMutableString *argumentsString = [NSMutableString stringWithString:@"ssh "];
if ([[NSUserDefaults standardUserDefaults] boolForKey:@"forceSSHVersion2"])
argumentsString = (NSMutableString *)[argumentsString stringByAppendingString:@" -2 "];
if ([self sessionTunnelType] == AMSessionOutgoingTunnel)
{
int i;
for(i = 0; i < [remotePorts count]; i++)
{
argumentsString = (NSMutableString *)[argumentsString stringByAppendingString:@" -N -L "];
argumentsString = (NSMutableString *)[argumentsString stringByAppendingString:[localPorts objectAtIndex:i]];
argumentsString = (NSMutableString *)[argumentsString stringByAppendingString:@":"];
argumentsString = (NSMutableString *)[argumentsString stringByAppendingString:remoteHost];
argumentsString = (NSMutableString *)[argumentsString stringByAppendingString:@":"];
argumentsString = (NSMutableString *)[argumentsString stringByAppendingString:[remotePorts objectAtIndex:i]];
}
}
else if ([self sessionTunnelType] == AMSessionIncomingTunnel)
{
int i;
for(i = 0; i < [remotePorts count]; i++)
{
argumentsString = (NSMutableString *)[argumentsString stringByAppendingString:@" -N -R "];
argumentsString = (NSMutableString *)[argumentsString stringByAppendingString:[remotePorts objectAtIndex:i]];
argumentsString = (NSMutableString *)[argumentsString stringByAppendingString:@":"];
argumentsString = (NSMutableString *)[argumentsString stringByAppendingString:@"127.0.0.1"];
argumentsString = (NSMutableString *)[argumentsString stringByAppendingString:@":"];
argumentsString = (NSMutableString *)[argumentsString stringByAppendingString:[localPorts objectAtIndex:i]];
}
}
if (([self useDynamicProxy] == YES) || ([self sessionTunnelType] == AMSessionGlobalProxy))
{
argumentsString = (NSMutableString *)[argumentsString stringByAppendingString:@" -D "];
argumentsString = (NSMutableString *)[argumentsString stringByAppendingString:[self globalProxyPort]];
}
argumentsString = (NSMutableString *)[argumentsString stringByAppendingString:@" "];
argumentsString = (NSMutableString *)[argumentsString stringByAppendingString:[currentServer username]];
argumentsString = (NSMutableString *)[argumentsString stringByAppendingString:@"@"];
argumentsString = (NSMutableString *)[argumentsString stringByAppendingString:[currentServer host]];
argumentsString = (NSMutableString *)[argumentsString stringByAppendingString:@" -p "];
argumentsString = (NSMutableString *)[argumentsString stringByAppendingString:[currentServer port]];
NSLog(@"Used SSH Command : %@", argumentsString);
return argumentsString;
}
#pragma mark Control methods
- (void) openTunnel
{
NSString *helperPath;
NSArray *args;
NSMutableArray *remotePorts;
NSMutableArray *localPorts;
NSMutableString *argumentsString;
//[self prepareAuthorization];
if ([self currentServer] == nil)
{
[self setConnected:NO];
[self setConnectionInProgress:NO];
[[NSNotificationCenter defaultCenter] postNotificationName:AMNewErrorMessage
object:@"There is no server set for this session."];
return;
}
if ([self sessionTunnelType] == AMSessionOutgoingTunnel)
{
if (([self remoteHost] == nil) ||
([self portsMap] == nil))
{
[self setConnected:NO];
[self setConnectionInProgress:NO];
[[NSNotificationCenter defaultCenter] postNotificationName:AMNewErrorMessage
object:@"There is no service or remote host set for this session"];
return;
}
}
else if ([self sessionTunnelType] == AMSessionIncomingTunnel)
{
if (([self portsMap] == nil) ||
(([self useDynamicProxy] == YES) && ([self globalProxyPort] == nil)))
{
[self setConnected:NO];
[self setConnectionInProgress:NO];
[[NSNotificationCenter defaultCenter] postNotificationName:AMNewErrorMessage
object:@"There is no services or dynamic port set for this session."];
return;
}
}
else if ([self sessionTunnelType] == AMSessionGlobalProxy)
{
if (([self networkService] == nil) ||
([self globalProxyPort] == nil))
{
[self setConnected:NO];
[self setConnectionInProgress:NO];
[[NSNotificationCenter defaultCenter] postNotificationName:AMNewErrorMessage
object:@"There is no dynamic port set for this session."];
return;
}
}
stdOut = [NSPipe pipe];
sshTask = [[NSTask alloc] init];
helperPath = [[NSBundle mainBundle] pathForResource:@"SSHCommand" ofType:@"sh"];
remotePorts = [self parsePortsSequence:[portsMap serviceRemotePorts]];
localPorts = [self parsePortsSequence:[portsMap serviceLocalPorts]];
argumentsString = [self prepareSSHCommandWithRemotePorts:remotePorts localPorts:localPorts];
args = [NSArray arrayWithObjects:argumentsString, [currentServer password], nil];
outputContent = @"";
[sshTask setLaunchPath:helperPath];
[sshTask setArguments:args];
[sshTask setStandardOutput:stdOut];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(handleProcessusExecution:)
name:NSFileHandleReadCompletionNotification
object:[[sshTask standardOutput] fileHandleForReading]];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(listernerForSSHTunnelDown:)
name:@"NSTaskDidTerminateNotification"
object:sshTask];
[[stdOut fileHandleForReading] readInBackgroundAndNotify];
[self setConnectionInProgress:YES];
NSError *error = nil;
[auth obtainWithRight:"system.privileges.admin"
flags:kAuthorizationFlagDefaults|kAuthorizationFlagInteractionAllowed|
kAuthorizationFlagExtendRights|kAuthorizationFlagPreAuthorize
error:&error];
[sshTask launch];
NSLog(@"Session %@ is now launched.", [self sessionName]);
[[NSNotificationCenter defaultCenter] postNotificationName:AMNewGeneralMessage
object:[@"Initializing connection for session "
stringByAppendingString:[self sessionName]]];
[self setStatusImagePath:[AMResourcesHelper pathForImageNamed:@"statusOrange"]];
helperPath = nil;
args = nil;
}
- (void) closeTunnel
{
if ([self sessionTunnelType] == AMSessionGlobalProxy)
[self setProxyEnableForThisSession:NO onPort:nil];
NSLog(@"Session %@ is now closed.", [self sessionName]);
if ([sshTask isRunning])
[sshTask terminate];
sshTask = nil;
}
#pragma mark Observers and delegates
- (void) handleProcessusExecution:(NSNotification *) aNotification
{
NSData *data;
NSPredicate *checkError;
NSPredicate *checkWrongPass;
NSPredicate *checkConnected;
NSPredicate *checkRefused;
NSPredicate *checkPort;
NSPredicate *checkLoggedIn;
data = [[aNotification userInfo] objectForKey:NSFileHandleNotificationDataItem];
outputContent = [outputContent stringByAppendingString:[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]];
checkError = [NSPredicate predicateWithFormat:@"SELF CONTAINS[cd] 'CONNECTION_ERROR'"];
checkWrongPass = [NSPredicate predicateWithFormat:@"SELF CONTAINS[cd] 'WRONG_PASSWORD'"];
checkConnected = [NSPredicate predicateWithFormat:@"SELF CONTAINS[cd] 'CONNECTED'"];
checkRefused = [NSPredicate predicateWithFormat:@"SELF CONTAINS[cd] 'CONNECTION_REFUSED'"];
checkPort = [NSPredicate predicateWithFormat:@"SELF CONTAINS[cd] 'Could not request local forwarding'"];
checkLoggedIn = [NSPredicate predicateWithFormat:@"SELF CONTAINS[cd] 'Last login:'"]; // This is for if there is a pub/priv key set up
if ([data length])
{
if ([checkError evaluateWithObject:outputContent] == YES)
{
[[NSNotificationCenter defaultCenter] removeObserver:self name:NSFileHandleReadCompletionNotification object:[stdOut fileHandleForReading]];
[self setStatusImagePath:[AMResourcesHelper pathForImageNamed:@"statusRed"]];
[self setConnected:NO];
[self setConnectionInProgress:NO];
[self setConnectionLink:@""];
[sshTask terminate];
[[NSNotificationCenter defaultCenter] postNotificationName:AMNewErrorMessage
object:[@"Unknown error for session "
stringByAppendingString:[self sessionName]]];
NSRunAlertPanel(@"Error while connecting", @"Unknown error as occured while connecting." , @"Ok", nil, nil);
}
else if ([checkWrongPass evaluateWithObject:outputContent] == YES)
{
[[NSNotificationCenter defaultCenter] removeObserver:self name:NSFileHandleReadCompletionNotification object:[stdOut fileHandleForReading]];
[self setConnected:NO];
[self setConnectionInProgress:NO];
[self setStatusImagePath:[AMResourcesHelper pathForImageNamed:@"statusRed"]];
[self setConnectionLink:@""];
[sshTask terminate];
[[NSNotificationCenter defaultCenter] postNotificationName:AMNewErrorMessage
object:[@"Wrong server password for session "
stringByAppendingString:[self sessionName]]];
NSRunAlertPanel(@"Error while connecting", @"The password or username set for the server are wrong" , @"Ok", nil, nil);
}
else if ([checkRefused evaluateWithObject:outputContent] == YES)
{
[[NSNotificationCenter defaultCenter] removeObserver:self name:NSFileHandleReadCompletionNotification object:[stdOut fileHandleForReading]];
[self setStatusImagePath:[AMResourcesHelper pathForImageNamed:@"statusRed"]];
[self setConnected:NO];
[self setConnectionInProgress:NO];
[self setConnectionLink:@""];
[sshTask terminate];
[[NSNotificationCenter defaultCenter] postNotificationName:AMNewErrorMessage
object:[@"Connection has been refused by server for session "
stringByAppendingString:[self sessionName]]];
NSRunAlertPanel(@"Error while connecting", @"Connection has been rejected by the server." , @"Ok", nil, nil);
}
else if ([checkPort evaluateWithObject:outputContent] == YES)
{
[[NSNotificationCenter defaultCenter] removeObserver:self name:NSFileHandleReadCompletionNotification object:[stdOut fileHandleForReading]];
[self setStatusImagePath:[AMResourcesHelper pathForImageNamed:@"statusRed"]];
[self setConnected:NO];
[self setConnectionInProgress:NO];
[self setConnectionLink:@""];
[sshTask terminate];
[[NSNotificationCenter defaultCenter] postNotificationName:AMNewErrorMessage
object:[@"Wrong server port for session "
stringByAppendingString:[self sessionName]]];
NSRunAlertPanel(@"Error while connecting", @"The port is already in used on server." , @"Ok", nil, nil);
}
else if ([checkConnected evaluateWithObject:outputContent] == YES || [checkLoggedIn evaluateWithObject:outputContent] == YES)
{
[[NSNotificationCenter defaultCenter] removeObserver:self name:NSFileHandleReadCompletionNotification object:[stdOut fileHandleForReading]];
[self setConnected:YES];
[self setConnectionInProgress:NO];
[self setStatusImagePath:[AMResourcesHelper pathForImageNamed:@"statusGreen"]];
[[NSNotificationCenter defaultCenter] postNotificationName:AMNewGeneralMessage
object:[@"Sucessfully connects session "
stringByAppendingString:[self sessionName]]];
if ([self sessionTunnelType] == AMSessionOutgoingTunnel)
[self setConnectionLink:[@"127.0.0.1:" stringByAppendingString:[portsMap serviceLocalPorts]]];
else if ([self sessionTunnelType] == AMSessionIncomingTunnel)
[self setConnectionLink:[[[self currentServer] host] stringByAppendingString:[@":" stringByAppendingString:[portsMap serviceRemotePorts]]]];
if ([self sessionTunnelType] == AMSessionGlobalProxy)
[self setProxyEnableForThisSession:YES onPort:globalProxyPort];
//[[NSPasteboard generalPasteboard] declareTypes:[NSArray arrayWithObject: NSStringPboardType] owner: nil];
//[[NSPasteboard generalPasteboard] setString:[self connectionLink] forType:NSStringPboardType];
}
else
[[stdOut fileHandleForReading] readInBackgroundAndNotify];
data = nil;
checkError = nil;
checkWrongPass = nil;
checkConnected = nil;
checkPort = nil;
}
}
- (void) listernerForSSHTunnelDown:(NSNotification *)notification
{
[[stdOut fileHandleForReading] closeFile];
[[NSNotificationCenter defaultCenter] removeObserver:self name:NSTaskDidTerminateNotification object:sshTask];
[self setConnected:NO];
[self setConnectionInProgress:NO];
[self setConnectionLink:@""];
[self setStatusImagePath:[AMResourcesHelper pathForImageNamed:@"statusRed"]];
[[NSNotificationCenter defaultCenter] postNotificationName:AMNewGeneralMessage
object:[@"Connection close for session "
stringByAppendingString:[self sessionName]]];
}
@end