author | Michael Krelin <hacker@klever.net> | 2012-12-08 21:19:17 (UTC) |
---|---|---|
committer | Michael Krelin <hacker@klever.net> | 2012-12-11 21:59:29 (UTC) |
commit | 8808689fe340bec6e90ab13dd502292b0579cf1f (patch) (side-by-side diff) | |
tree | 45b7c863151341f687b74e40bffcbd7ab5468783 /pumpkin/SendXFer.m | |
parent | 6e7e413ca364d79673e523c09767c18e7cff1bec (diff) | |
download | pumpkin-osx/0.0.zip pumpkin-osx/0.0.tar.gz pumpkin-osx/0.0.tar.bz2 |
initial osx portosx/0.0
Signed-off-by: Michael Krelin <hacker@klever.net>
-rw-r--r-- | pumpkin/SendXFer.m | 156 |
1 files changed, 156 insertions, 0 deletions
diff --git a/pumpkin/SendXFer.m b/pumpkin/SendXFer.m new file mode 100644 index 0000000..9a1d85b --- a/dev/null +++ b/pumpkin/SendXFer.m @@ -0,0 +1,156 @@ +#import "SendXFer.h" +#import "StringsAttached.h" +#import "ConfirmRequest.h" + +@implementation SendXFer + +-(SendXFer*)initWithLocalFile:(NSString *)lf peerAddress:(const struct sockaddr_in *)pa remoteFile:(NSString *)rf xferType:(NSString *)xt blockSize:(uint16_t)bs andTimeout:(int)to { + if(!(self = [super init])) return self; + xferPrefix = @"⬆"; + retryTimeout = to; + localFile = lf; + memmove(&peer,pa,sizeof(peer)); + if(!(theFile = [[NSFileHandle fileHandleForReadingAtPath:localFile] retain])) { + [pumpkin log:@"Failed to open '%@', transfer aborted.",localFile]; + return self; + } + + long xb = ((xferSize=[theFile seekToEndOfFile])/blockSize)+1; + if(xb > UINT16_MAX) { + [pumpkin log:@"file is too big (%lld bytes) and will take %ld blocks to be sent with block size of %d bytes",xferSize,xb,blockSize]; + return self; + } + xferBlocks = xb; + + [self createSocket]; + NSMutableDictionary *o = [NSMutableDictionary dictionaryWithCapacity:4]; + [o setValue:[NSString stringWithFormat:@"%u",bs] forKey:@"blksize"]; + [o setValue:[NSString stringWithFormat:@"%llu",xferSize] forKey:@"tsize"]; + [o setValue:[NSString stringWithFormat:@"%d",(int)retryTimeout] forKey:@"timeout"]; + state = xferStateConnecting; + [self queuePacket:[TFTPPacket packetWRQWithFile:xferFilename=rf xferType:xferType=xt andOptions:o]]; + [self appear]; + return self; +} + +-(SendXFer*)initWithPeer:(struct sockaddr_in *)sin andPacket:(TFTPPacket*)p { + if(!(self = [super initWithPeer:sin andPacket:p])) return self; + xferPrefix = @"⬆"; + xferFilename = [p.rqFilename retain]; xferType = [p.rqType retain]; + [pumpkin log:@"'%@' of type '%@' is requested from %@", + xferFilename, xferType, [NSString stringWithSocketAddress:&peer] ]; + + [self createSocket]; + [self appear]; + + if(![self makeLocalFileName:xferFilename]) + return self; + + switch([[pumpkin.theDefaults.values valueForKey:@"rrqBehavior"] intValue]) { + case onRRQDeny: [self goOnWithVerdict:verdictDeny]; break; + case onRRQGive: [self goOnWithVerdict:verdictAllow]; break; + default: + [ConfirmRequest confirmationWithXfer:self]; + break; + } + return self; +} +-(void)goOnWithVerdict:(int)verdict { + if(verdict!=verdictAllow) { + [self queuePacket:[TFTPPacket packetErrorWithCode:tftpErrAccessViolation andMessage:@"Access denied"]]; + return; + } + if(!(theFile = [[NSFileHandle fileHandleForReadingAtPath:localFile] retain])) { + [self queuePacket:[TFTPPacket packetErrorWithErrno:errno andFallback:@"couldn't open file"]]; + return; + } + xferSize = [theFile seekToEndOfFile]; + NSMutableDictionary *o = [NSMutableDictionary dictionaryWithCapacity:4]; + [[initialPacket rqOptions] enumerateKeysAndObjectsUsingBlock:^(NSString* k, NSString* v, BOOL *stop) { + if([k isEqualToString:@"blksize"]) { + [o setValue:[NSString stringWithFormat:@"%u",blockSize=v.intValue] forKey:@"blksize"]; + }else if([k isEqualToString:@"tsize"]) { + [o setValue:[NSString stringWithFormat:@"%lld",xferSize] forKey:@"tsize"]; + }else if([k isEqualToString:@"timeout"]) { + [o setValue:[NSString stringWithFormat:@"%d",v.intValue] forKey:@"timeout"]; + retryTimeout = v.intValue; + }else + [pumpkin log:@"Unknown option '%@' with value '%@'. Ignoring.",k,v]; + }]; + long xb = (xferSize/blockSize)+1; + if(xb > UINT16_MAX) { + [self queuePacket:[TFTPPacket packetErrorWithCode:tftpErrUndefined andMessage:[NSString stringWithFormat:@"file is too big (%lld bytes) and will take %ld blocks to be sent with block size of %d bytes",xferSize,xb,blockSize]]]; + return; + } + xferBlocks = xb; + state = xferStateXfer; + if(o.count) { + [self queuePacket:[TFTPPacket packetOACKWithOptions:o]]; + }else{ + [self xfer]; + } +} + +- (void) xfer { + NSAssert(theFile,@"no file!"); + [theFile seekToFileOffset:acked*blockSize]; + [self queuePacket:[TFTPPacket packetDataWithBlock:acked+1 andData:[theFile readDataOfLength:blockSize]]]; +} + +- (void) eatTFTPPacket:(TFTPPacket*)p from:(struct sockaddr_in*)sin{ + if(state==xferStateConnecting) { + peer.sin_port = sin->sin_port; + [self updateView]; + }else if(![self isPeer:sin]) { + [pumpkin log:@"Packet from unexpected source (%@) recevied",[NSString stringWithSocketAddress:sin]]; + return; + } + switch(p.op) { + case tftpOpACK: + if(state==xferStateShutdown || ( (acked=p.block)==xferBlocks && (state=xferStateShutdown) ) ) { + CFSocketEnableCallBacks(sockie, kCFSocketWriteCallBack); + return; + } + [self updateView]; + [self xfer]; + break; + case tftpOpERROR: + [pumpkin log:@"Error %u:%@",p.rqCode, p.rqMessage]; + [self updateView]; + [self disappear]; + return; + case tftpOpOACK: + if(acked) { + [pumpkin log:@"It's a bit too late to acknowledge options, ignoring OACK packet"]; + break; + } + { + __block BOOL a=NO; + [p.rqOptions enumerateKeysAndObjectsUsingBlock:^(NSString *k,NSString *v,BOOL *s) { + if([k isEqualToString:@"blksize"]) + blockSize = v.intValue; + else if([k isEqualToString:@"tsize"]) { + }else if([k isEqualToString:@"timeout"]) + retryTimeout = v.intValue; + else{ + [pumpkin log:@"Totally unknown option '%@' with value '%@' acknowledged by peer",k,v]; + a=YES; + } + }]; + if(a) { + [self abort]; + break; + } + state = xferStateXfer; + [self updateView]; + [self xfer]; + } + break; + default: + [pumpkin log:@"Totaly unexpected opcode %d received",p.op]; + break; + } +} + + +@end |