1 /*----------------------------------------------------------------------------
2 Name: xmlBlasterZlib.c
3 Project: xmlBlaster.org
4 Copyright: xmlBlaster.org, see xmlBlaster-LICENSE file
5 Comment: Contains some socket specific helper methods
6 Author: "Marcel Ruff" <xmlBlaster@marcelruff.info>
7 -----------------------------------------------------------------------------*/
8 #include <stdio.h>
9 #include <string.h>
10 #include <assert.h>
11 #include <socket/xmlBlasterZlib.h>
12 #include <socket/xmlBlasterSocket.h> /* writen() */
13 #ifdef __IPhoneOS__
14 #include <CoreFoundation/CFSocket.h>
15 #include <XmlBlasterConnectionUnparsed.h>
16 #endif
17
18 #if XMLBLASTER_ZLIB==1
19
20 /*
21 TODO:
22 valgrind reports with zlib-1.2.1
23 ==24008== Conditional jump or move depends on uninitialised value(s)
24 ==24008== at 0x8051823: longest_match (deflate.c:949)
25 ==24008== by 0x8052691: deflate_slow (deflate.c:1422)
26 ==24008== by 0x8050F19: deflate (deflate.c:630)
27 ==24008== by 0x804BE78: xmlBlaster_writenCompressed (xmlBlasterZlib.c:102)
28
29 See a discussion of this:
30 http://www.groupsrv.com/science/viewtopic.php?t=19234&start=0&postdays=0&postorder=asc&highlight=
31 (http://www.gammon.com.au/forum/bbshowpost.php?bbsubject_id=4000)
32
33 Example:
34 XmlBlasterZlibWriteBuffers zlibWriteBuf;
35
36 if (xmlBlaster_initZlibWriter(zlibWriteBufP) != Z_OK) return -1;
37
38 while () {
39 ...
40 ssize_t num = xmlBlaster_writenCompressed(&zlibWriteBuf, socketFd, buffer, nbytes);
41 }
42
43
44 XmlBlasterZlibReadBuffers zlibReadBuf;
45 if (xmlBlaster_initZlibReader(&zlibReadBuf) != Z_OK) return -1;
46
47 */
48
49 /**
50 * Helper for debugging.
51 */
52 static void dumpZlib(const char *p, XmlBlasterZlibReadBuffers *zlibReadBufP, XmlBlasterZlibWriteBuffers *zlibWriteBufP) {
53 z_stream *zlibP = (zlibReadBufP!=0) ? &zlibReadBufP->c_stream : &zlibWriteBufP->c_stream;
54 printf("[%s:%d] %s\n", __FILE__, __LINE__, p);
55 printf("{\n");
56 if (zlibReadBufP!=0) {
57 /*printf(" compBufferP ="PRINTF_PREFIX_UINT64_T"\n", (uint64_t)zlibReadBufP->compBuffer);*/
58 printf(" compBufferP =%p\n", zlibReadBufP->compBuffer);
59 printf(" currCompBufferP =%p\n", zlibReadBufP->currCompBufferP);
60 printf(" currCompBytes =%d\n", (int)zlibReadBufP->currCompBytes);
61 }
62 printf(" zlibP->next_in =%p\n", zlibP->next_in);
63 printf(" zlibP->avail_in =%d\n", (int)zlibP->avail_in);
64 printf(" zlibP->next_out =%p\n", zlibP->next_out);
65 printf(" zlibP->avail_out=%u\n", zlibP->avail_out);
66 printf("}\n");
67 }
68
69 /**
70 * @see xmlBlasterZlib.h
71 */
72 int xmlBlaster_initZlibWriter(XmlBlasterZlibWriteBuffers *zlibWriteBufP) {
73 int err;
74
75 if (!zlibWriteBufP) return Z_BUF_ERROR;
76 memset(zlibWriteBufP, 0, sizeof(XmlBlasterZlibWriteBuffers));
77
78 zlibWriteBufP->debug = false;
79
80 zlibWriteBufP->c_stream.zalloc = (alloc_func)0;
81 zlibWriteBufP->c_stream.zfree = (free_func)0;
82 zlibWriteBufP->c_stream.opaque = (voidpf)0;
83 zlibWriteBufP->c_stream.data_type = Z_BINARY;
84
85 err = deflateInit(&zlibWriteBufP->c_stream, Z_DEFAULT_COMPRESSION);
86 if (err != Z_OK) {
87 fprintf(stderr, "[%s:%d] deflateInit error: %s\n", __FILE__, __LINE__, zError(err));
88 }
89 return err;
90 }
91
92
93 /**
94 * @see xmlBlasterZlib.h
95 */
96 ssize_t xmlBlaster_writenCompressed(XmlBlasterZlibWriteBuffers *zlibWriteBufP, const int fd, const char * const ptr, const size_t nbytes)
97 {
98 size_t written = 0; /* The written bytes of the compressed stream */
99 if (!zlibWriteBufP) {
100 fprintf(stderr, "[%s:%d] Internal error: XmlBlasterZlibWriteBuffers is NULL\n", __FILE__, __LINE__);
101 return -1;
102 }
103
104 {
105 z_stream *zlibP = &zlibWriteBufP->c_stream;
106 bool onceMore = false;
107
108 /* Initialize zlib buffer pointers */
109 zlibP->next_in = (Bytef*)ptr;
110 zlibP->avail_in = (uInt)nbytes;
111 zlibP->next_out = zlibWriteBufP->compBuffer;
112 zlibP->avail_out = XMLBLASTER_ZLIB_WRITE_COMPBUFFER_LEN;
113
114 if (zlibWriteBufP->debug) dumpZlib("writen(): Before while", 0, zlibWriteBufP);
115
116 /* Compress and write to socket */
117
118 while (zlibP->avail_in > 0 || onceMore) {
119 int status = deflate(zlibP, Z_SYNC_FLUSH);
120 if (zlibWriteBufP->debug) dumpZlib("writen(): In while after compress", 0, zlibWriteBufP);
121 if (status != Z_OK) {
122 fprintf(stderr, "[%s:%d] deflate error during sending of %u bytes: %s\n", __FILE__, __LINE__, (unsigned int)nbytes, zError(status));
123 return -1;
124 }
125 onceMore = zlibP->avail_out == 0; /* && Z_OK which is checked above already */
126 if ((XMLBLASTER_ZLIB_WRITE_COMPBUFFER_LEN - zlibP->avail_out) > 0) {
127 /*if (zlibP->avail_out <= 6) { */ /* with Z_SYNC_FLUSH we should not go down to zero */
128 ssize_t ret = writen(fd, (char *)zlibWriteBufP->compBuffer, XMLBLASTER_ZLIB_WRITE_COMPBUFFER_LEN-zlibP->avail_out);
129 if (ret == -1) return -1;
130 written += ret;
131 zlibP->next_out = zlibWriteBufP->compBuffer;
132 zlibP->avail_out = XMLBLASTER_ZLIB_WRITE_COMPBUFFER_LEN;
133 }
134 }
135 if (zlibWriteBufP->debug) dumpZlib("writen(): After compress", 0, zlibWriteBufP);
136 /*
137 if ((XMLBLASTER_ZLIB_WRITE_COMPBUFFER_LEN - zlibP->avail_out) > 0) {
138 ret = writen(fd, (char *)zlibWriteBufP->compBuffer, XMLBLASTER_ZLIB_WRITE_COMPBUFFER_LEN-zlibP->avail_out);
139 if (ret == -1) return -1;
140 written += ret;
141 }
142 */
143 if (zlibWriteBufP->debug) printf("deflate - compressed %u bytes to %u\n", (unsigned int)nbytes, (unsigned int)written);
144
145 return nbytes; /*written*/
146 }
147 }
148
149
150 /**
151 * @see xmlBlasterZlib.h
152 */
153 int xmlBlaster_endZlibWriter(XmlBlasterZlibWriteBuffers *zlibWriteBufP) {
154 int err;
155 if (!zlibWriteBufP) return Z_BUF_ERROR;
156 if (zlibWriteBufP->debug) dumpZlib("writen(): After compress", 0, zlibWriteBufP);
157 err = deflateEnd(&zlibWriteBufP->c_stream);
158 if (err != Z_OK) {
159 /* TODO: Why does it return "-3 == data error"? Seems to be in BUSY_STATE */
160 /*fprintf(stderr, "[%s:%d] deflateEnd error: %s\n", __FILE__, __LINE__, zError(err));*/
161 return -1;
162 }
163 return err;
164 }
165
166
167 /**
168 * @see xmlBlasterZlib.h
169 */
170 int xmlBlaster_initZlibReader(XmlBlasterZlibReadBuffers *zlibReadBufP) {
171 int err;
172
173 if (!zlibReadBufP) return Z_BUF_ERROR;
174 memset(zlibReadBufP, 0, sizeof(XmlBlasterZlibReadBuffers));
175
176 zlibReadBufP->debug = false;
177
178 zlibReadBufP->c_stream.zalloc = (alloc_func)0;
179 zlibReadBufP->c_stream.zfree = (free_func)0;
180 zlibReadBufP->c_stream.opaque = (voidpf)0;
181
182 err = inflateInit(&zlibReadBufP->c_stream);
183 if (err != Z_OK) {
184 fprintf(stderr, "[%s:%d] inflateInit error: %s\n", __FILE__, __LINE__, zError(err));
185 }
186
187 zlibReadBufP->currCompBufferP = zlibReadBufP->compBuffer;
188 zlibReadBufP->currCompBytes = 0;
189
190 return err;
191 }
192
193
194 /**
195 * @see xmlBlasterZlib.h
196 */
197 ssize_t xmlBlaster_readnCompressed(XmlBlasterZlibReadBuffers *zlibReadBufP, int fd, char *ptr, size_t nbytes, XmlBlasterNumReadFunc fpNumRead, void *userP2)
198 {
199 uInt readBytes = 0; /* The read, uncompressed bytes */
200
201 if (!zlibReadBufP) {
202 fprintf(stderr, "[%s:%d] Internal error: XmlBlasterZlibReadBuffers is NULL\n", __FILE__, __LINE__);
203 return -1;
204 }
205
206 {
207 z_stream *zlibP = &zlibReadBufP->c_stream;
208
209 if (zlibReadBufP->debug) printf("[%s:%d] Entering readnCompressed ...\n", __FILE__, __LINE__);
210
211 /* Initialize zlib buffer pointers */
212 zlibP->next_out = (Bytef*)ptr;
213 zlibP->avail_out = (uInt)nbytes;
214
215 if (zlibReadBufP->currCompBytes == 0)
216 zlibReadBufP->currCompBufferP = zlibReadBufP->compBuffer;
217 zlibP->next_in = zlibReadBufP->currCompBufferP;
218 zlibP->avail_in = zlibReadBufP->currCompBytes;
219
220 if (zlibReadBufP->debug) dumpZlib("readn(): Before do", zlibReadBufP, 0);
221
222 /* Read from socket and uncompress */
223 do {
224 if (fpNumRead != 0) {
225 fpNumRead(userP2, (size_t)zlibP->next_out-(size_t)ptr, nbytes); /* Callback with current status */
226 }
227 if (zlibP->avail_out == 0) {
228 if (zlibReadBufP->debug) printf("[%s:%d] readCompress() we are done with nbytes=%u currCompBytes=%u\n", __FILE__, __LINE__, (unsigned int)nbytes, zlibReadBufP->currCompBytes);
229 if (fpNumRead != 0) {
230 fpNumRead(userP2, nbytes, nbytes);
231 }
232 return nbytes;
233 }
234
235 if (zlibReadBufP->currCompBytes == 0 && readBytes != nbytes) {
236 const int flag = 0;
237 ssize_t nCompRead;
238 if (zlibReadBufP->debug) printf("[%s:%d] recv() readBytes=%u, nbytes=%u, currCompBytes=%u\n", __FILE__, __LINE__, readBytes, (unsigned int)nbytes, zlibReadBufP->currCompBytes);
239 zlibReadBufP->currCompBufferP = zlibReadBufP->compBuffer;
240 /* currCompBufferP is of type "Bytef *" which is a "unsigned char *" */
241 #ifdef __IPhoneOS__
242 /* if(CFReadStreamHasBytesAvailable ( globalIPhoneXb->readStream )) */
243 nCompRead = CFReadStreamRead (
244 globalIPhoneXb->readStream,
245 (UInt8*)zlibReadBufP->currCompBufferP,
246 (CFIndex) 5
247 );
248
249 #else
250 nCompRead = recv(fd, (char*)zlibReadBufP->currCompBufferP, (int)XMLBLASTER_ZLIB_READ_COMPBUFFER_LEN, flag); /* TODO: do we need at least two bytes?? */
251 #endif
252 if (nCompRead == -1 || nCompRead == 0) { /* 0 is not possible as we are blocking */
253 if (zlibReadBufP->debug) printf("[%s:%d] EOF during reading of %u bytes\n", __FILE__, __LINE__, (unsigned int)(nbytes-readBytes));
254 return -1;
255 }
256 zlibReadBufP->currCompBytes += (uInt)nCompRead;
257 zlibP->next_in = zlibReadBufP->currCompBufferP;
258 zlibP->avail_in = zlibReadBufP->currCompBytes;
259 if (zlibReadBufP->debug) dumpZlib("readn(): recv() returned", zlibReadBufP, 0);
260 }
261
262 while (zlibP->avail_in > 0 && zlibP->avail_out > 0) {
263 int status = inflate(zlibP, Z_SYNC_FLUSH);
264 if (status != Z_OK) {
265 fprintf(stderr, "[%s:%d] inflate error during reading of %u bytes: %s\n", __FILE__, __LINE__, (unsigned int)nbytes, zError(status));
266 return -1;
267 }
268 zlibReadBufP->currCompBufferP = zlibP->next_in;
269 zlibReadBufP->currCompBytes = zlibP->avail_in;
270 if (zlibReadBufP->debug) dumpZlib("readn(): inflate() returned", zlibReadBufP, 0);
271 if (zlibP->avail_out == 0) {
272 if (zlibReadBufP->debug) printf("[%s:%d] readCompress() we are done with nbytes=%u\n", __FILE__, __LINE__, (unsigned int)nbytes);
273 if (fpNumRead != 0) {
274 fpNumRead(userP2, nbytes, nbytes);
275 }
276 return nbytes;
277 }
278 }
279 } while(true);
280
281 /* check if bytes are available
282 int hasMoreBytes;
283 fd_set fds;
284 FD_ZERO(&fds);
285 FD_SET(fd, &fds);
286 hasMoreBytes = select (fd+1, &fds, NULL, NULL, NULL);
287 */
288 }
289 return -1; /* never reached, to make compiler happy */
290 }
291
292
293 /**
294 * @see xmlBlasterZlib.h
295 */
296 int xmlBlaster_endZlibReader(XmlBlasterZlibReadBuffers *zlibReadBufP) {
297 int err;
298 if (!zlibReadBufP) return Z_BUF_ERROR;
299 err = inflateEnd(&zlibReadBufP->c_stream);
300 if (err != Z_OK) {
301 fprintf(stderr, "[%s:%d] inflateEnd error: %s\n", __FILE__, __LINE__, zError(err));
302 return -1;
303 }
304 return err;
305 }
306
307 #else
308
309 /* If no zlib is available use dummies: */
310 int xmlBlaster_initZlibWriter(XmlBlasterZlibWriteBuffers *zlibWriteBufP) {
311 fprintf(stderr, "No support for zlib is compiled, try with -DXMLBLASTER_ZLIB=1\n");
312 assert(0);
313 zlibWriteBufP = 0;/* to supress compiler warning */
314 return 0;
315 }
316 ssize_t xmlBlaster_writenCompressed(XmlBlasterZlibWriteBuffers *zlibWriteBufP, const int fd, const char * const ptr, const size_t nbytes) {
317 if (fd && ptr && nbytes) zlibWriteBufP = 0;/* to supress compiler warning */
318 return 0;
319 }
320 int xmlBlaster_endZlibWriter(XmlBlasterZlibWriteBuffers *zlibWriteBufP) { zlibWriteBufP = 0;/* to supress compiler warning */ return -1; }
321 int xmlBlaster_initZlibReader(XmlBlasterZlibReadBuffers *zlibReadBufP) { zlibReadBufP = 0;/* to supress compiler warning */ return -1; }
322 ssize_t xmlBlaster_readnCompressed(XmlBlasterZlibReadBuffers *zlibReadBufP, int fd, char *ptr, size_t nbytes, XmlBlasterNumReadFunc fpNumRead, void *userP2) {
323 if (fd && ptr && nbytes && fpNumRead && userP2) zlibReadBufP = 0;/* to supress compiler warning */
324 return 0;
325 }
326 int xmlBlaster_endZlibReader(XmlBlasterZlibReadBuffers *zlibReadBufP) { zlibReadBufP = 0;/* to supress compiler warning */ return -1; }
327
328 # endif /* XMLBLASTER_ZLIB */
syntax highlighted by Code2HTML, v. 0.9.1