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) (unidiff) | |
tree | 45b7c863151341f687b74e40bffcbd7ab5468783 /pumpkin/TFTPPacket.m | |
parent | 6e7e413ca364d79673e523c09767c18e7cff1bec (diff) | |
download | pumpkin-8808689fe340bec6e90ab13dd502292b0579cf1f.zip pumpkin-8808689fe340bec6e90ab13dd502292b0579cf1f.tar.gz pumpkin-8808689fe340bec6e90ab13dd502292b0579cf1f.tar.bz2 |
initial osx portosx/0.0
Signed-off-by: Michael Krelin <hacker@klever.net>
-rw-r--r-- | pumpkin/TFTPPacket.m | 203 |
1 files changed, 203 insertions, 0 deletions
diff --git a/pumpkin/TFTPPacket.m b/pumpkin/TFTPPacket.m new file mode 100644 index 0000000..73f5995 --- a/dev/null +++ b/pumpkin/TFTPPacket.m | |||
@@ -0,0 +1,203 @@ | |||
1 | |||
2 | #import "TFTPPacket.h" | ||
3 | |||
4 | @interface NSDictionary (TFTPOptions) | ||
5 | |||
6 | - (size_t)tftpBytesLength; | ||
7 | - (size_t)tftpGetBytes:(char*)p maxLength:(size_t)ml; | ||
8 | |||
9 | @end | ||
10 | @implementation NSDictionary (TFTPOptions) | ||
11 | |||
12 | - (size_t)tftpBytesLength { | ||
13 | __block size_t rv = 0; | ||
14 | [self enumerateKeysAndObjectsUsingBlock:^(id k,id v,BOOL *s) { | ||
15 | rv += [k lengthOfBytesUsingEncoding:NSUTF8StringEncoding]+[v lengthOfBytesUsingEncoding:NSUTF8StringEncoding]+2; | ||
16 | }]; | ||
17 | return rv; | ||
18 | } | ||
19 | |||
20 | - (size_t)tftpGetBytes:(char*)p maxLength:(size_t)ml { | ||
21 | __block char *_p = p; | ||
22 | __block size_t rl = ml; | ||
23 | __block size_t rv = 0; | ||
24 | [self enumerateKeysAndObjectsUsingBlock:^(NSString *k,NSString *v,BOOL *s) { | ||
25 | NSUInteger l; | ||
26 | [k getBytes:_p maxLength:rl usedLength:&l encoding:NSUTF8StringEncoding options:0 range:NSMakeRange(0,k.length) remainingRange:NULL]; | ||
27 | _p+=l; *_p++=0; rl-=l+1; rv+=l+1; | ||
28 | [v getBytes:_p maxLength:rl usedLength:&l encoding:NSUTF8StringEncoding options:0 range:NSMakeRange(0,v.length) remainingRange:NULL]; | ||
29 | _p+=l; *_p++=0; rl-=l+1; rv+=l+1; | ||
30 | }]; | ||
31 | return rv; | ||
32 | } | ||
33 | |||
34 | @end | ||
35 | |||
36 | @implementation TFTPPacket | ||
37 | @synthesize data; | ||
38 | |||
39 | -(BOOL) isRQOp { | ||
40 | return self.op==tftpOpRRQ || self.op==tftpOpWRQ; | ||
41 | } | ||
42 | -(BOOL) isOptionsOp { | ||
43 | return self.isRQOp || self.op==tftpOpOACK; | ||
44 | } | ||
45 | -(BOOL) isBlockOp { | ||
46 | return self.op==tftpOpDATA || self.op==tftpOpACK; | ||
47 | } | ||
48 | |||
49 | -(enum TFTPOp)op { | ||
50 | NSAssert(data.length,@"no data"); | ||
51 | return (enum TFTPOp)ntohs(packet->op); | ||
52 | } | ||
53 | -(NSString*)rqFilename { | ||
54 | NSAssert( self.isRQOp, @"Wrong TFTP opcode for rq filename retrieval"); | ||
55 | if(!memchr(packet->rq.data, 0, [data length]-sizeof(packet->op))) return nil; | ||
56 | return @(packet->rq.data); | ||
57 | } | ||
58 | -(NSString*)rqType { | ||
59 | NSAssert( self.isRQOp, @"Wrong TFTP opcode for rq type retrieval"); | ||
60 | const char *z = (const char*)memchr(packet->rq.data,0, data.length-sizeof(packet->op)); | ||
61 | if(!z) return nil; | ||
62 | if(!memchr(z+1,0,data.length-sizeof(packet->op)-(z-packet->rq.data))) return nil; | ||
63 | return @(z+1); | ||
64 | } | ||
65 | -(NSDictionary*)rqOptions { | ||
66 | enum TFTPOp op = self.op; | ||
67 | NSAssert( self.isOptionsOp, @"Wrong TFTP opcode for options retrieval"); | ||
68 | const char *p = packet->any.data, *p1 = (const char*)packet + data.length; | ||
69 | if(op==tftpOpRRQ || op==tftpOpWRQ) { | ||
70 | p = (const char *)memchr(p,0,p1-p); | ||
71 | if(!p) return nil; | ||
72 | p = (const char *)memchr(p+1,0,p1-p); | ||
73 | if(!p) return nil; | ||
74 | ++p; | ||
75 | } | ||
76 | NSMutableDictionary *rv = [NSMutableDictionary dictionaryWithCapacity:8]; | ||
77 | while(p<p1) { | ||
78 | const char *on = p; | ||
79 | p = (const char *)memchr(p,0,p1-p); | ||
80 | if(!p) break; | ||
81 | const char *ov = ++p; | ||
82 | p = (const char *)memchr(p,0,p1-p); | ||
83 | if(!p) break; | ||
84 | ++p; | ||
85 | rv[[@(on) lowercaseString]] = @(ov); | ||
86 | } | ||
87 | return rv; | ||
88 | } | ||
89 | -(uint16_t)block { | ||
90 | NSAssert( self.isBlockOp, @"Wrong TFTP opcode for block number retrieval"); | ||
91 | return ntohs(*(uint16_t*)&packet->data); | ||
92 | } | ||
93 | -(NSData*)rqData { | ||
94 | NSAssert( self.op==tftpOpDATA, @"Can't get data from the request that doesn't have it"); | ||
95 | return [NSData dataWithBytes:packet->data.data length:data.length-sizeof(packet->op)-sizeof(packet->data.block)]; | ||
96 | } | ||
97 | -(uint16_t)rqCode { | ||
98 | NSAssert(self.op==tftpOpERROR,@"Wrong TFTP opcode for error code retrieval"); | ||
99 | return ntohs(packet->err.code); | ||
100 | } | ||
101 | -(NSString*)rqMessage { | ||
102 | NSAssert(self.op==tftpOpERROR,@"Wrong TFTP opcode for error message retrieval"); | ||
103 | return @(packet->err.data); | ||
104 | } | ||
105 | |||
106 | -(TFTPPacket*)initWithData:(NSData *)d { | ||
107 | if(!(self = [super init])) return self; | ||
108 | packet = (struct AnyTFTPPacket*)(data = [d retain]).bytes; | ||
109 | return self; | ||
110 | } | ||
111 | |||
112 | |||
113 | +(TFTPPacket*)packetWithData:(NSData*)d { | ||
114 | return [[[self alloc] initWithData:d] autorelease]; | ||
115 | } | ||
116 | +(TFTPPacket*)packetWithBytesNoCopy:(void*)b andLength:(size_t)l { | ||
117 | return [[[self alloc] initWithData:[NSData dataWithBytesNoCopy:b length:l]] autorelease]; | ||
118 | } | ||
119 | |||
120 | +(TFTPPacket*)packetErrorWithCode:(enum TFTPError)c andMessage:(NSString*)m { | ||
121 | NSUInteger ml = [m lengthOfBytesUsingEncoding:NSUTF8StringEncoding], bb; | ||
122 | struct AnyTFTPPacket *b = (struct AnyTFTPPacket*)malloc(bb = sizeof(b->op)+sizeof(b->err.code)+ml+1); | ||
123 | if(!b) return nil; | ||
124 | b->op = htons(tftpOpERROR); | ||
125 | b->err.code = ntohs(c); | ||
126 | [m getBytes:b->err.data maxLength:ml usedLength:NULL encoding:NSUTF8StringEncoding options:0 range:NSMakeRange(0,m.length) remainingRange:NULL]; | ||
127 | b->err.data[ml]=0; | ||
128 | return [self packetWithBytesNoCopy:b andLength:bb]; | ||
129 | } | ||
130 | +(TFTPPacket*)packetErrorWithErrno:(int)en andFallback:(NSString *)fb{ | ||
131 | switch(en) { | ||
132 | case EACCES: | ||
133 | return [self packetErrorWithCode:tftpErrAccessViolation andMessage:@"acess violation"]; | ||
134 | case ENOENT: | ||
135 | return [self packetErrorWithCode:tftpErrNotFound andMessage:@"not found"]; | ||
136 | } | ||
137 | return [self packetErrorWithCode:tftpErrUndefined andMessage:fb]; | ||
138 | } | ||
139 | |||
140 | +(TFTPPacket*)packetXRQWithOp:(enum TFTPOp)op file:(NSString*)f xferType:(NSString*)t andOptions:(NSDictionary*)o { | ||
141 | NSAssert(f && t && o,@"Something is amiss in packetXRQWithOp"); | ||
142 | __block size_t dl = o.tftpBytesLength | ||
143 | +[f lengthOfBytesUsingEncoding:NSUTF8StringEncoding] | ||
144 | +[t lengthOfBytesUsingEncoding:NSUTF8StringEncoding] | ||
145 | +2; | ||
146 | size_t pl = dl; | ||
147 | struct AnyTFTPPacket *b = (struct AnyTFTPPacket*)malloc(pl+=sizeof(b->op)); | ||
148 | if(!b) return nil; | ||
149 | b->op = htons(op); | ||
150 | __block char *p = b->rrq.data; | ||
151 | NSUInteger l; | ||
152 | [f getBytes:p maxLength:dl usedLength:&l encoding:NSUTF8StringEncoding options:0 range:NSMakeRange(0,f.length) remainingRange:NULL]; | ||
153 | p+=l; *p++=0; dl-=l+1; | ||
154 | [t getBytes:p maxLength:dl usedLength:&l encoding:NSUTF8StringEncoding options:0 range:NSMakeRange(0,t.length) remainingRange:NULL]; | ||
155 | p+=l; *p++=0; dl-=l+1; | ||
156 | l = [o tftpGetBytes:p maxLength:dl]; | ||
157 | p+=l; dl-=l; | ||
158 | NSAssert1(dl==0,@"packet of the wrong size, remaining count: %lu",dl); | ||
159 | return [self packetWithBytesNoCopy:b andLength:pl]; | ||
160 | } | ||
161 | |||
162 | +(TFTPPacket*)packetRRQWithFile:(NSString *)f xferType:(NSString *)t andOptions:(NSDictionary *)o { | ||
163 | return [self packetXRQWithOp:tftpOpRRQ file:f xferType:t andOptions:o]; | ||
164 | } | ||
165 | +(TFTPPacket*)packetWRQWithFile:(NSString *)f xferType:(NSString *)t andOptions:(NSDictionary *)o { | ||
166 | return [self packetXRQWithOp:tftpOpWRQ file:f xferType:t andOptions:o]; | ||
167 | } | ||
168 | |||
169 | +(TFTPPacket*)packetOACKWithOptions:(NSDictionary*)o { | ||
170 | __block NSUInteger pl = [o tftpBytesLength]; | ||
171 | __block NSUInteger rc = pl; | ||
172 | __block struct AnyTFTPPacket *b = (struct AnyTFTPPacket*)malloc(pl+=sizeof(b->op)); | ||
173 | if(!b) return nil; | ||
174 | b->op = htons(tftpOpOACK); | ||
175 | __block char *p = b->oack.data; | ||
176 | rc -= [o tftpGetBytes:p maxLength:pl]; | ||
177 | NSAssert1(rc==0,@"packet of the wrong size, remaining count: %lu",rc); | ||
178 | return [self packetWithBytesNoCopy:b andLength:pl]; | ||
179 | } | ||
180 | +(TFTPPacket*)packetDataWithBlock:(uint16_t)b andData:(NSData*)d { | ||
181 | NSUInteger pl; | ||
182 | struct AnyTFTPPacket *p = (struct AnyTFTPPacket*)malloc(pl=sizeof(p->op)+sizeof(p->data.block)+d.length); | ||
183 | if(!p) return nil; | ||
184 | p->op = htons(tftpOpDATA); | ||
185 | p->data.block = htons(b); | ||
186 | [d getBytes:p->data.data length:d.length]; | ||
187 | return [self packetWithBytesNoCopy:p andLength:pl]; | ||
188 | } | ||
189 | +(TFTPPacket*)packetACKWithBlock:(uint16_t)b { | ||
190 | NSUInteger pl; | ||
191 | struct AnyTFTPPacket *p = (struct AnyTFTPPacket*)malloc(pl=sizeof(p->op)+sizeof(p->ack.block)); | ||
192 | if(!p) return nil; | ||
193 | p->op = htons(tftpOpACK); | ||
194 | p->ack.block = htons(b); | ||
195 | return [self packetWithBytesNoCopy:p andLength:pl]; | ||
196 | } | ||
197 | |||
198 | -(void)dealloc { | ||
199 | [data release]; | ||
200 | [super dealloc]; | ||
201 | } | ||
202 | |||
203 | @end | ||