/
AppDelegate.m
186 lines (158 loc) · 4.82 KB
/
AppDelegate.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
//
// AppDelegate.m
// Multicast Ping
//
// Copyright 2010 bdunagan.com. All rights reserved.
//
#import "AppDelegate.h"
#import "Message.h"
#import <Security/AuthorizationTags.h>
@implementation AppDelegate
#pragma mark -
#pragma mark User Interface
- (void)awakeFromNib {
// Setup model storage.
messages = [[NSMutableArray alloc] init];
// Setup interface.
[self stopProcessing];
// Setup security.
AuthorizationItem items = {kAuthorizationRightExecute, 0, NULL, 0};
AuthorizationRights rights = {1, &items};
[authView setAuthorizationRights:&rights];
authView.delegate = self;
[authView updateStatus:nil];
helperPath = [[[NSBundle mainBundle] pathForAuxiliaryExecutable:@"multicast_tester"] retain];
}
- (IBAction)clickStartButton:(id)sender {
if (helperHandle == nil) {
BOOL didLaunch = [self launchHelper];
if (didLaunch) {
[self startProcessing];
}
else {
[self stopProcessing];
}
}
else {
[self stopProcessing];
}
}
- (void)startProcessing {
// Hide any error message.
[errorMessage setHidden:YES];
// Update button title.
[startButton setTitle:@"Stop"];
// Hide spinner.
[spinner startAnimation:nil];
[spinner setHidden:NO];
}
- (void)stopProcessing {
// Update button title.
[startButton setTitle:@"Start"];
// Hide spinner.
[spinner setHidden:YES];
[spinner stopAnimation:nil];
// Close pipe to terminate the helper tool.
[helperHandle closeFile];
helperHandle = nil;
}
#pragma mark -
#pragma mark NSTableView Data Source
- (int)numberOfRowsInTableView:(NSTableView *)aTableView {
return [messages count];
}
- (id)tableView:(NSTableView *)aTableView objectValueForTableColumn:(NSTableColumn *)aTableColumn row:(int)rowIndex {
if ([[aTableColumn identifier] isEqual:@"Name"]) {
return [[messages objectAtIndex:rowIndex] name];
}
else if ([[aTableColumn identifier] isEqual:@"Message"]) {
return [[messages objectAtIndex:rowIndex] message];
}
else {
return nil;
}
}
#pragma mark -
#pragma mark Controller
- (void)applicationWillTerminate:(NSNotification *)notification {
if (helperHandle != nil) {
[self stopProcessing];
}
}
- (void)dealloc {
[self stopProcessing];
[helperPath release];
[messages release];
[super dealloc];
}
- (BOOL)launchHelper {
// Get address and port.
NSString *address = [addressField stringValue];
NSString *port = [portField stringValue];
// Collect arguments into an array.
NSMutableArray *args = [NSMutableArray array];
[args addObject:[NSString stringWithFormat:@"%@", address]];
[args addObject:[NSString stringWithFormat:@"%@", port]];
// Convert array into void-* array.
const char **argv = (const char **)malloc(sizeof(char *) * [args count] + 1);
int currentIndex = 0;
for (currentIndex = 0; currentIndex < [args count]; currentIndex++) {
argv[currentIndex] = [[args objectAtIndex:currentIndex] UTF8String];
}
argv[currentIndex] = nil;
// Execute the command with privileges from SFAuthorizationView.
FILE *handle;
OSErr processError = AuthorizationExecuteWithPrivileges([[authView authorization] authorizationRef], [helperPath UTF8String],
kAuthorizationFlagDefaults, (char *const *)argv, &handle);
free(argv);
if (processError != 0) {
NSLog(@"helper tool failed (%d)", processError);
return NO;
}
// Setup the two-way pipe.
helperHandle = [[NSFileHandle alloc] initWithFileDescriptor:fileno(handle)];
[helperHandle waitForDataInBackgroundAndNotify];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleTaskOutput:) name:NSFileHandleDataAvailableNotification object:helperHandle];
return YES;
}
- (void)handleTaskOutput:(NSNotification *)notification {
// Get the new data.
NSFileHandle *handle = (NSFileHandle *)[notification object];
NSData *data = [handle availableData];
if ([data length] > 0) {
// Convert the data into a string.
NSString *dataString = [[NSString alloc] initWithBytes:[data bytes] length:[data length] encoding:NSUTF8StringEncoding];
if ([dataString isEqual:@"port in use"]) {
// Tool failed.
[self handleToolFailure];
[dataString release];
return;
}
// Process the string, expecting "address,port,message".
NSArray *array = [dataString componentsSeparatedByString:@","];
[dataString release];
if ([array count] == 3) {
// Get attributes.
NSString *address = [array objectAtIndex:0];
int port = [[array objectAtIndex:1] intValue];
NSString *message = [array objectAtIndex:2];
// Create new message.
Message *newMessage = [[Message alloc] initWithAddress:address andPort:port andMessage:message];
[messages addObject:newMessage];
[newMessage release];
// Update view.
[listView reloadData];
}
// Prepare for more data.
[handle waitForDataInBackgroundAndNotify];
}
else {
// No data means tool failed.
[self handleToolFailure];
}
}
- (void)handleToolFailure {
[self stopProcessing];
[errorMessage setHidden:NO];
}
@end