Oolite 1.91.0.7604-240417-a536cbe
Loading...
Searching...
No Matches
OOTCPStreamDecoder.c
Go to the documentation of this file.
1/*
2
3OOTCPStreamDecoder.c
4
5
6Copyright (C) 2007 Jens Ayton and contributors
7
8Permission is hereby granted, free of charge, to any person obtaining a copy
9of this software and associated documentation files (the "Software"), to deal
10in the Software without restriction, including without limitation the rights
11to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12copies of the Software, and to permit persons to whom the Software is
13furnished to do so, subject to the following conditions:
14
15The above copyright notice and this permission notice shall be included in all
16copies or substantial portions of the Software.
17
18THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24SOFTWARE.
25
26*/
27
28#ifndef OO_EXCLUDE_DEBUG_SUPPORT
29
30
31#include "OOTCPStreamDecoder.h"
32#include <stdlib.h>
33#include <stdarg.h>
34#include <stdint.h>
36
37
38#ifdef OO_LOG_DEBUG_PROTOCOL_PACKETS
40#else
41#define LogOOTCPStreamDecoderPacket(packet) do {} while (0)
42#endif
43
44
58
59
60static void Error(OOTCPStreamDecoderRef decoder, OOALStringRef format, ...);
61static void PacketReady(OOTCPStreamDecoderRef decoder);
62
63
65{
66 OOTCPStreamDecoderRef decoder = NULL;
67
68 if (packetCB == NULL) return NULL;
69
70 decoder = malloc(sizeof *decoder);
71 if (decoder == NULL) return NULL;
72
73 decoder->headerSpaceUsed = 0;
74 decoder->nextPacketData = NULL;
75 decoder->nextSize = 0;
76 decoder->Packet = packetCB;
77 decoder->Error = errorCB;
78 decoder->Finalize = finalizeCB;
79 decoder->cbInfo = cbInfo;
80
81 return decoder;
82}
83
84
86{
87 if (decoder == NULL) return;
88
89 if (decoder->Finalize != NULL)
90 {
91 decoder->Finalize(decoder->cbInfo);
92 }
93
94 if (decoder->nextPacketData != NULL)
95 {
97 decoder->nextPacketData = NULL;
98 }
99
100 free(decoder);
101}
102
103
105{
106 if (decoder == NULL || data == NULL) return;
107
109}
110
111
112void OOTCPStreamDecoderReceiveBytes(OOTCPStreamDecoderRef decoder, const void *inBytes, size_t length)
113{
114 const unsigned char *bytes = NULL;
115 size_t remaining;
116 size_t bytesToAdd;
117 OOALAutoreleasePoolRef pool = NULL;
118
119 if (decoder == NULL) return;
120
121 bytes = inBytes;
122 remaining = length;
123
124 if (bytes == NULL && remaining != 0)
125 {
126 Error(decoder, OOALSTR("Invalid data -- NULL bytes but %u byte count."), remaining);
127 return;
128 }
129
130 while (remaining != 0)
131 {
132 if (decoder->nextPacketData != NULL)
133 {
134 // More data expected
135 bytesToAdd = remaining;
136 if (decoder->nextSize < bytesToAdd) bytesToAdd = decoder->nextSize;
137
138 OOALMutableDataAppendBytes(decoder->nextPacketData, bytes, bytesToAdd);
139
140 remaining -= bytesToAdd;
141 decoder->nextSize -= bytesToAdd;
142 bytes += bytesToAdd;
143
144 if (decoder->nextSize == 0)
145 {
146 // Packet is ready.
148 PacketReady(decoder);
150 pool = NULL;
151
152 OOALRelease(decoder->nextPacketData);
153 decoder->nextPacketData = NULL;
154 }
155 }
156 else if (decoder->headerSpaceUsed < 4)
157 {
158 // Read bytes for packet header
159 remaining--;
160 decoder->header[decoder->headerSpaceUsed++] = *bytes++;
161 }
162 else if (decoder->headerSpaceUsed == 4)
163 {
164 // We've read a header, start on a packet.
165 decoder->nextSize = (decoder->header[0] << 24) |
166 (decoder->header[1] << 16) |
167 (decoder->header[2] << 8) |
168 (decoder->header[3] << 0);
169
170 decoder->headerSpaceUsed = 0;
171 if (decoder->nextSize != 0)
172 {
173 decoder->nextPacketData = OOALDataCreateMutable(decoder->nextSize);
174 }
175 }
176 else
177 {
178 Error(decoder, OOALSTR("OOTCPStreamDecoder internal error: reached unreachable state. nextSize = %lu, bufferUsed = %lu, nextPacketData = %@."), (unsigned long)decoder->nextSize, (unsigned long)decoder->headerSpaceUsed, decoder->nextPacketData);
179 }
180 }
181}
182
183
185{
186 OOALDictionaryRef packet = NULL;
187 OOALStringRef errorString = NULL;
188 OOALStringRef packetType = NULL;
189
190 packet = OOALPropertyListFromData(decoder->nextPacketData, &errorString);
191
192 // Ensure that it's a property list.
193 if (packet == NULL)
194 {
195 Error(decoder, OOALSTR("Protocol error: packet is not property list (property list error: %@)."), errorString);
196 OOALRelease(errorString);
197 return;
198 }
199
200 // Ensure that it's a dictionary.
201 if (!OOALIsDictionary(packet))
202 {
203 Error(decoder, OOALSTR("Protocol error: packet is a %@, not a dictionary."), OOTypeDescription(packet));
204 return;
205 }
206
208
209 // Get packet type (and ensure that there is one).
210 packetType = OOALDictionaryGetValue(packet, kOOTCPPacketType);
211 if (packetType == NULL)
212 {
213 Error(decoder, OOALSTR("Protocol error: packet contains no packet type."));
214 return;
215 }
216
217 if (!OOALIsString(packetType))
218 {
219 Error(decoder, OOALSTR("Protocol error: packet type is a %@, not a string."), OOTypeDescription(packetType));
220 return;
221 }
222
223 decoder->Packet(decoder->cbInfo, packetType, packet);
224}
225
226
227static void Error(OOTCPStreamDecoderRef decoder, OOALStringRef format, ...)
228{
229 va_list args;
230 OOALStringRef string = NULL;
231
232 if (decoder == NULL || decoder->Error == NULL || format == NULL) return;
233
234 va_start(args, format);
235 string = OOALStringCreateWithFormatAndArguments(format, args);
236 va_end(args);
237
238 if (string != NULL)
239 {
240 decoder->Error(decoder->cbInfo, string);
241 OOALRelease(string);
242 }
243}
244
245#endif /* OO_EXCLUDE_DEBUG_SUPPORT */
#define OOALSTR(x)
#define kOOTCPPacketType
OOALStringRef OOTypeDescription(OOALObjectRef object)
bool OOALIsDictionary(OOALObjectRef object)
OOALStringRef OOALStringCreateWithFormatAndArguments(OOALStringRef format, va_list args)
const struct NSAutoreleasePool * OOALAutoreleasePoolRef
void OOALMutableDataAppendBytes(OOALMutableDataRef data, const void *bytes, size_t length)
const void * OOALDataGetBytePtr(OOALDataRef data)
const struct NSString * OOALStringRef
size_t OOALDataGetLength(OOALDataRef data)
OOALObjectRef OOALDictionaryGetValue(OOALDictionaryRef dictionary, OOALObjectRef key)
#define OOALDestroyAutoreleasePool(pool)
const struct NSDictionary * OOALDictionaryRef
bool OOALIsString(OOALObjectRef object)
OOALAutoreleasePoolRef OOALCreateAutoreleasePool(void)
struct NSData * OOALMutableDataRef
OOALMutableDataRef OOALDataCreateMutable(size_t capacity)
void OOALRelease(OOALObjectRef object)
OOALObjectRef OOALPropertyListFromData(OOALMutableDataRef data, OOALStringRef *errStr)
const struct NSData * OOALDataRef
OOTCPStreamDecoderRef OOTCPStreamDecoderCreate(OOTCPStreamDecoderPacketCallback packetCB, OOTCPStreamDecoderErrorCallback errorCB, OOTCPStreamDecoderFinalizeCallback finalizeCB, void *cbInfo)
static void PacketReady(OOTCPStreamDecoderRef decoder)
void OOTCPStreamDecoderReceiveBytes(OOTCPStreamDecoderRef decoder, const void *inBytes, size_t length)
void OOTCPStreamDecoderDestroy(OOTCPStreamDecoderRef decoder)
static void Error(OOTCPStreamDecoderRef decoder, OOALStringRef format,...)
void OOTCPStreamDecoderReceiveData(OOTCPStreamDecoderRef decoder, OOALDataRef data)
#define LogOOTCPStreamDecoderPacket(packet)
void(* OOTCPStreamDecoderFinalizeCallback)(void *cbInfo)
void(* OOTCPStreamDecoderPacketCallback)(void *cbInfo, OOALStringRef packetType, OOALDictionaryRef packet)
void(* OOTCPStreamDecoderErrorCallback)(void *cbInfo, OOALStringRef errorDesc)
OOTCPStreamDecoderFinalizeCallback Finalize
OOALMutableDataRef nextPacketData
OOTCPStreamDecoderErrorCallback Error
OOTCPStreamDecoderPacketCallback Packet