summaryrefslogtreecommitdiffabout
path: root/pumpkin/DaemonListener.m
Unidiff
Diffstat (limited to 'pumpkin/DaemonListener.m') (more/less context) (ignore whitespace changes)
-rw-r--r--pumpkin/DaemonListener.m111
1 files changed, 111 insertions, 0 deletions
diff --git a/pumpkin/DaemonListener.m b/pumpkin/DaemonListener.m
new file mode 100644
index 0000000..ab14296
--- a/dev/null
+++ b/pumpkin/DaemonListener.m
@@ -0,0 +1,111 @@
1#import "DaemonListener.h"
2#import "TFTPPacket.h"
3#import "SendXFer.h"
4#import "ReceiveXFer.h"
5#import "StringsAttached.h"
6
7#include <sys/socket.h>
8#include <arpa/inet.h>
9#include <sys/stat.h>
10
11static void cbListener(CFSocketRef sockie,CFSocketCallBackType cbt,CFDataRef cba,
12 const void *cbd,void *i) {
13 [(DaemonListener*)i callbackWithType:cbt addr:cba data:cbd];
14}
15
16@implementation DaemonListener
17
18-(void)callbackWithType:(CFSocketCallBackType)t addr:(CFDataRef)a data:(const void *)d {
19 switch(t) {
20 case kCFSocketDataCallBack:
21 {
22 struct sockaddr_in *sin = (struct sockaddr_in*)CFDataGetBytePtr(a);
23 if([pumpkin hasPeer:sin]) {
24 [pumpkin log:@"I'm already processing the request from %@",[NSString stringWithSocketAddress:sin]];
25 return;
26 }
27 TFTPPacket *p = [TFTPPacket packetWithData:(NSData*)d];
28 switch([p op]) {
29 case tftpOpRRQ: [[[SendXFer alloc] initWithPeer:sin andPacket:p] autorelease]; break;
30 case tftpOpWRQ: [[[ReceiveXFer alloc] initWithPeer:sin andPacket:p] autorelease]; break;
31 default:
32 [pumpkin log:@"Invalid OP %d received from %@",p.op,[NSString stringWithSocketAddress:sin]];
33 break;
34 }
35 }
36 break;
37 default:
38 NSLog(@"unhandled callback: %lu",t);
39 break;
40 }
41}
42
43
44-(DaemonListener*)initWithAddress:(struct sockaddr_in*)sin {
45 if(!(self=[super init])) return self;
46
47 pumpkin = NSApplication.sharedApplication.delegate;
48
49 @try {
50 CFSocketContext ctx;
51 ctx.version = 0;
52 ctx.info = self;
53 ctx.retain = 0; ctx.release = 0;
54 ctx.copyDescription = 0;
55 sockie = CFSocketCreate(kCFAllocatorDefault,PF_INET,SOCK_DGRAM,IPPROTO_UDP,
56 kCFSocketReadCallBack|kCFSocketDataCallBack,
57 cbListener,&ctx);
58 if(ntohs(sin->sin_port)>1024) {
59 NSData *nsd = [NSData dataWithBytes:sin length:sizeof(*sin)];
60 if(CFSocketSetAddress(sockie, (CFDataRef)nsd))
61 [[NSException exceptionWithName:@"BindFailure"
62 reason:[NSString stringWithFormat:@"Binding failed, error code: %d", errno]
63 userInfo:@{@"errno": @errno}
64 ] raise];
65 }else{
66 const char *args[] = {
67 0,
68 [[NSString stringWithFormat:@"%d", CFSocketGetNative(sockie)] UTF8String],
69 [[NSString stringWithHostAddress:sin] UTF8String],
70 [[NSString stringWithPortNumber:sin] UTF8String],
71 NULL
72 };
73 [pumpkin runBiportal:args];
74 }
75 }@catch(NSException *e) {
76 if(sockie) {
77 CFSocketInvalidate(sockie);
78 CFRelease(sockie);
79 }
80 @throw;
81 }
82
83 runloopSource = CFSocketCreateRunLoopSource(kCFAllocatorDefault, sockie, 0);
84 CFRunLoopAddSource(CFRunLoopGetCurrent(),runloopSource, kCFRunLoopDefaultMode);
85 return self;
86}
87
88-(void)dealloc {
89 if(runloopSource) {
90 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), runloopSource, kCFRunLoopDefaultMode);
91 CFRelease(runloopSource);
92 }
93 if(sockie) {
94 CFSocketInvalidate(sockie);
95 CFRelease(sockie);
96 }
97 [super dealloc];
98}
99
100+(DaemonListener*) listenerWithDefaults {
101 struct sockaddr_in sin;
102 memset(&sin,0,sizeof(sin));
103 sin.sin_len=sizeof(sin);
104 sin.sin_family=AF_INET;
105 id d = [[NSUserDefaultsController sharedUserDefaultsController] values];
106 sin.sin_port=htons([[d valueForKey:@"bindPort"] intValue]);
107 sin.sin_addr.s_addr=inet_addr([[d valueForKey:@"bindAddress"] UTF8String]);
108 return [[[DaemonListener alloc] initWithAddress:&sin] autorelease];
109}
110
111@end