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