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
|
#import "DaemonListener.h"
#import "TFTPPacket.h"
#import "SendXFer.h"
#import "ReceiveXFer.h"
#import "StringsAttached.h"
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/stat.h>
static void cbListener(CFSocketRef sockie,CFSocketCallBackType cbt,CFDataRef cba,
const void *cbd,void *i) {
[(DaemonListener*)i callbackWithType:cbt addr:cba data:cbd];
}
@implementation DaemonListener
-(void)callbackWithType:(CFSocketCallBackType)t addr:(CFDataRef)a data:(const void *)d {
switch(t) {
case kCFSocketDataCallBack:
{
struct sockaddr_in *sin = (struct sockaddr_in*)CFDataGetBytePtr(a);
if([pumpkin hasPeer:sin]) {
[pumpkin log:@"I'm already processing the request from %@",[NSString stringWithSocketAddress:sin]];
return;
}
TFTPPacket *p = [TFTPPacket packetWithData:(NSData*)d];
switch([p op]) {
case tftpOpRRQ: [[[SendXFer alloc] initWithPeer:sin andPacket:p] autorelease]; break;
case tftpOpWRQ: [[[ReceiveXFer alloc] initWithPeer:sin andPacket:p] autorelease]; break;
default:
[pumpkin log:@"Invalid OP %d received from %@",p.op,[NSString stringWithSocketAddress:sin]];
break;
}
}
break;
default:
NSLog(@"unhandled callback: %lu",t);
break;
}
}
-(DaemonListener*)initWithAddress:(struct sockaddr_in*)sin {
if(!(self=[super init])) return self;
pumpkin = NSApplication.sharedApplication.delegate;
@try {
CFSocketContext ctx;
ctx.version = 0;
ctx.info = self;
ctx.retain = 0; ctx.release = 0;
ctx.copyDescription = 0;
sockie = CFSocketCreate(kCFAllocatorDefault,PF_INET,SOCK_DGRAM,IPPROTO_UDP,
kCFSocketReadCallBack|kCFSocketDataCallBack,
cbListener,&ctx);
if(ntohs(sin->sin_port)>1024) {
NSData *nsd = [NSData dataWithBytes:sin length:sizeof(*sin)];
if(CFSocketSetAddress(sockie, (CFDataRef)nsd))
[[NSException exceptionWithName:@"BindFailure"
reason:[NSString stringWithFormat:@"Binding failed, error code: %d", errno]
userInfo:@{@"errno": @errno}
] raise];
}else{
const char *args[] = {
0,
[[NSString stringWithFormat:@"%d", CFSocketGetNative(sockie)] UTF8String],
[[NSString stringWithHostAddress:sin] UTF8String],
[[NSString stringWithPortNumber:sin] UTF8String],
NULL
};
[pumpkin runBiportal:args];
}
}@catch(NSException *e) {
if(sockie) {
CFSocketInvalidate(sockie);
CFRelease(sockie);
}
@throw;
}
runloopSource = CFSocketCreateRunLoopSource(kCFAllocatorDefault, sockie, 0);
CFRunLoopAddSource(CFRunLoopGetCurrent(),runloopSource, kCFRunLoopDefaultMode);
return self;
}
-(void)dealloc {
if(runloopSource) {
CFRunLoopRemoveSource(CFRunLoopGetCurrent(), runloopSource, kCFRunLoopDefaultMode);
CFRelease(runloopSource);
}
if(sockie) {
CFSocketInvalidate(sockie);
CFRelease(sockie);
}
[super dealloc];
}
+(DaemonListener*) listenerWithDefaults {
struct sockaddr_in sin;
memset(&sin,0,sizeof(sin));
sin.sin_len=sizeof(sin);
sin.sin_family=AF_INET;
id d = [[NSUserDefaultsController sharedUserDefaultsController] values];
sin.sin_port=htons([[d valueForKey:@"bindPort"] intValue]);
sin.sin_addr.s_addr=inet_addr([[d valueForKey:@"bindAddress"] UTF8String]);
return [[[DaemonListener alloc] initWithAddress:&sin] autorelease];
}
@end
|