1 /*----------------------------------------------------------------------------
  2 Name:      xmlBlasterSocket.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 <socket/xmlBlasterSocket.h>
 11 #ifdef __IPhoneOS__
 12 #include <CoreFoundation/CFSocket.h>
 13 #include <XmlBlasterConnectionUnparsed.h>
 14 #endif
 15 
 16 void closeSocket(int fd) {
 17 #ifdef _WINDOWS
 18    closesocket(fd);
 19 #else
 20    (void)close(fd);
 21 #endif
 22 }
 23 
 24 #ifdef __IPhoneOS__
 25 bool isIPhoneSocketConnectionEstablished(XmlBlasterConnectionUnparsed *xb) {
 26 while(!CFWriteStreamCanAcceptBytes(xb->writeStream))
 27 {
 28    if(xb == 0 || xb->writeStream == nil)
 29       return false;
 30    
 31    CFErrorRef errorRef = CFWriteStreamCopyError (xb->writeStream);
 32    if(errorRef != 0)
 33    {
 34       CFStringRef stringRef = CFErrorCopyDescription(errorRef);
 35       char buff[1000];
 36       CFStringGetCString (
 37                      stringRef,
 38                      buff,
 39                      1000,
 40                      kCFStringEncodingUTF8
 41                      );
 42       printf("\nxmlBlasterSocket.c writen() Warning writing to Network is not possible, reason is: %s\n", buff);
 43       CFRelease(errorRef);
 44       return false;
 45    }
 46    sleepMillis(100);
 47 }
 48    return true;
 49 }
 50 #endif
 51 
 52 /**
 53  * Write the given amount of bytes to socket.
 54  * This method blocks until data all data is sent, we loop
 55  * as the low level write() can return when the socket
 56  * buffer is full but not all data expected are sent.
 57  *
 58  * This code is not thread safe, you need to add a mutex to
 59  * your calling code if two threads simultaneously want to read
 60  * from the same socket 'fd'.
 61  *
 62  * @return number of bytes written, -1 is EOF
 63  * @author W. Richard Stevens
 64  */
 65 ssize_t writen(const int fd, const char * ptr, const size_t nbytes)
 66 {
 67 #ifdef __IPhoneOS__
 68 #  pragma unused(fd) /*if (fd < 200) printf("xmlBlasterSocket.c: dummy printf to avoid compiler warning\n");*/
 69    
 70         /*      CFTimeInterval timeOut = -1;
 71          CFSocketRef socketRef = globalIPhoneXb->cfSocketRef;
 72          CFDataRef dataRef = CFDataCreate(kCFAllocatorDefault, (void*) ptr, nbytes);
 73          CFSocketError cfSocketError = CFSocketSendData(socketRef, globalIPhoneXb->socketAddr, dataRef, timeOut);
 74          if(cfSocketError == kCFSocketError) return -1;
 75          */
 76         ssize_t nleft, nwritten;
 77 
 78       if (isIPhoneSocketConnectionEstablished(globalIPhoneXb) == false)
 79       return -1;
 80         
 81         
 82         nleft = (ssize_t)nbytes;
 83         while(nleft > 0) {
 84                 nwritten =  CFWriteStreamWrite (
 85                                                                                 globalIPhoneXb->writeStream,
 86                                                                                 (UInt8*) ptr,
 87                                                                                 (CFIndex) nbytes);
 88                 if(nwritten < 0)
 89                 {
 90                         CFErrorRef errorRef = CFWriteStreamCopyError (globalIPhoneXb->writeStream);
 91                         
 92                         if(errorRef != 0)
 93                         {
 94                                 CFStringRef stringRef = CFErrorCopyDescription(errorRef);
 95                                 char buff[1000];
 96                                 CFStringGetCString (
 97                                                                         stringRef,
 98                                                                         buff,
 99                                                                         1000,
100                                                                         kCFStringEncodingUTF8
101                                                                         );
102                                 printf("xmlBlasterSocket.c writen() Warning send %lu failed, reason is  %s\n", nbytes, buff);
103                                 CFRelease(errorRef);
104                         }
105                         return -1;
106                 }       
107                 else if (nwritten == 0) {
108                 if(CFWriteStreamGetStatus(globalIPhoneXb->writeStream) == kCFStreamStatusAtEnd)
109                             break; 
110                         else
111                                 continue;
112                 }       
113                 nleft -= nwritten;
114                 ptr += nwritten;
115         }
116         /*printf("Write %d bytes to XmlBlaster\n", nbytes);*/
117         return (ssize_t)nbytes - nleft;
118 #else
119         ssize_t nleft, nwritten;
120         int flag = 0; /* MSG_WAITALL; */
121 
122         nleft = (ssize_t)nbytes;
123         while(nleft > 0) {
124                 nwritten = send(fd, ptr, (int)nleft, flag); /* write() is deprecated on Win */
125                 if (nwritten <= 0) {
126                         return nwritten; /* error */
127                 }
128                 nleft -= nwritten;
129                 ptr += nwritten;
130         }
131         return (ssize_t)nbytes - nleft;
132 #endif
133 }
134 
135 /**
136  * Read the given amount of bytes from socket.
137  * This method blocks until data arrives, we loop
138  * as the low level recv() can return when the socket
139  * buffer is empty but not all data expected arrived.
140  *
141  * This code is not thread safe, you need to add a mutex to
142  * your calling code if two threads simultaneously want to read
143  * from the same socket 'fd'.
144  *
145  * @param fd The socket descriptor
146  * @param ptr A buffer which is big enough to hold nbytes
147  * @param nbytes The number of bytes to read
148  * @param fpNumRead Function pointer, if not null we make a callback about the progress
149  * @param userP Is bounced back to fpNumRead
150  * @return number of bytes read, -1 is EOF
151  * @author W. Richard Stevens
152  */
153 ssize_t readn(const int fd, char *ptr, const size_t nbytes, XmlBlasterNumReadFunc fpNumRead, void *userP)
154 {
155 #ifdef __IPhoneOS__
156         ssize_t nread;
157         ssize_t nleft;
158         nleft = (ssize_t)nbytes;
159    
160 #  pragma unused(fd, fpNumRead, userP) /*if (fd < 200 || fpNumRead == 0|| userP == 0) printf("xmlBlasterSocket.c: dummy printf to avoid compiler warning\n");*/
161         
162         /*
163          while(!CFReadStreamHasBytesAvailable(globalIPhoneXb->readStream)) 
164          {
165          usleep(100);
166          }
167          */
168         while(nleft > 0) {
169                 if (globalIPhoneXb->readStream == nil)
170                         return -1;
171                 
172                 nread =  CFReadStreamRead (
173                                                                    globalIPhoneXb->readStream,
174                                                                    (UInt8*) ptr,
175                                                                    (CFIndex) nleft
176                                                                    );
177                 if(nread < 0)
178                 {
179                         CFErrorRef errorRef = CFReadStreamCopyError (globalIPhoneXb->readStream);
180                         if(errorRef != 0)
181                         {
182                                 CFStringRef stringRef = CFErrorCopyDescription(errorRef);
183                                 CFStringRef reasonRef = 0;
184                                 char buff[1000];
185                                 CFStringGetCString (
186                                                                         stringRef,
187                                                                         buff,
188                                                                         1000,
189                                                                         kCFStringEncodingUTF8
190                                                                         );
191                                 printf("\nxmlBlasterSocket.c readn() Warning recv failed, nread is %u, description is '%s'\n", (unsigned int)nread, buff);
192                                 
193                                 reasonRef = CFErrorCopyFailureReason (
194                                                                                                                                   errorRef
195                                                                                                                                   );
196                                 CFStringGetCString (
197                                                                         reasonRef,
198                                                                         buff,
199                                                                         1000,
200                                                                         kCFStringEncodingUTF8
201                                                                         );
202                                 printf("xmlBlasterSocket.c readn() Warning recv failed, reason is  %s\n", buff);
203                                 
204                                 CFRelease(errorRef);
205                         }
206                         return -1;
207                 }
208                 else if(nread == 0)
209                 {
210              if(CFReadStreamGetStatus(globalIPhoneXb->readStream) == kCFStreamStatusAtEnd)
211                 break;
212              else
213                 continue;
214                                  
215                 }
216                 nleft -= nread;
217                 
218                 ptr += nread;
219         }
220         return (ssize_t)nbytes-nleft;
221         
222 #else
223    ssize_t nread;
224    ssize_t nleft;
225    int flag = 0; /* MSG_WAITALL; */
226    nleft = (ssize_t)nbytes;
227 
228    if (fpNumRead != 0 && nbytes > 10) { /* Ignore to report the msgLength read (first 10 bytes of a message) */
229       fpNumRead(userP, (ssize_t)0, nbytes); /* Callback with startup status */
230    }
231 
232    while(nleft > 0) {
233       nread = recv(fd, ptr, (int)nleft, flag); /* read() is deprecated on Win */
234       if (nread <= 0)  /* -1 is error, 0 is no more data to read which should not happen as we are blocking */
235          break;        /* EOF is -1 */
236       nleft -= nread;
237 
238       if (fpNumRead != 0 && nbytes > 10) { /* Ignore to report the msgLength read (first 10 bytes of a message) */
239          fpNumRead(userP, (ssize_t)nbytes-nleft, nbytes); /* Callback with current status */
240       }
241 
242       ptr += nread;
243    }
244    return (ssize_t)nbytes-nleft;
245 #endif
246 
247 }
248 
249 /**
250  * Check if the given arguments mark a oneway message.
251  * @param msgType The message type like MSG_TYPE_INVOKE
252  * @param methodName The name of the invoked message like "publish", can be null
253  * @return if true it is treated as oneway
254  */
255 bool xbl_isOneway(XMLBLASTER_MSG_TYPE msgType, const char *const methodName) {
256    if (msgType==MSG_TYPE_RESPONSE || msgType==MSG_TYPE_EXCEPTION)
257       return true; /* Responses and exceptions are oneway */
258    if (methodName == 0)
259       return false;
260    if (
261        !strcmp(XMLBLASTER_PUBLISH_ONEWAY, methodName)
262        /*|| !strcmp(XMLBLASTER_DISCONNECT, methodName)*/ /* according to protocol.socket it returns an ACK: shall we remove it? */
263        ) return true;
264    return false;
265 }
266 
267 /**
268  * Creates a raw blob to push over a socket as described in protocol.socket
269  * @param msgUnit The message which we need to send
270  * @param debug Pass true for debugging output to stdout
271  * @see http://www.xmlblaster.org/xmlBlaster/doc/requirements/protocol.socket.html
272  * @return The raw 'serialized' MsgUnit as a char* in BlobHolder, the caller needs to free() it.
273  */
274 Dll_Export BlobHolder encodeMsgUnit(MsgUnit *msgUnit, bool debug)
275 {
276    size_t qosLen=0, keyLen=0, contentLenStrLen=0;
277    enum { SIZE = 126 };
278    char contentLenStr[SIZE];
279    size_t currpos = 0;
280    BlobHolder blob;
281    memset(&blob, 0, sizeof(BlobHolder));
282 
283    if (msgUnit == 0) {
284       if (debug) printf("[xmlBlasterSocket] ERROR Invalid msgUnit=NULL in encodeMsgUnit()\n");
285       return blob;
286    }
287    if (msgUnit->content == 0)
288       msgUnit->contentLen = 0;
289    SNPRINTF(contentLenStr, SIZE, "%ld", (long)msgUnit->contentLen);
290    contentLenStrLen = strlen(contentLenStr);
291 
292    if (msgUnit->qos != 0)
293       qosLen = strlen(msgUnit->qos);
294 
295    if (msgUnit->key != 0)
296       keyLen = strlen(msgUnit->key);
297 
298    blob.dataLen = qosLen + 1 + keyLen + 1 + contentLenStrLen + 1 + msgUnit->contentLen;
299 
300    blob.data = (char *)malloc(blob.dataLen);
301 
302    if (msgUnit->qos != 0)
303       memcpy(blob.data+currpos, msgUnit->qos, qosLen+1); /* inclusive '\0' */
304    else
305       *(blob.data+currpos) = 0;
306    currpos += qosLen+1;
307 
308    if (msgUnit->key != 0)
309       memcpy(blob.data+currpos, msgUnit->key, keyLen+1); /* inclusive '\0' */
310    else
311       *(blob.data+currpos) = 0;
312    currpos += keyLen+1;
313 
314    memcpy(blob.data+currpos, contentLenStr, contentLenStrLen+1); /* inclusive '\0' */
315    currpos += contentLenStrLen+1;
316 
317    if (msgUnit->content != 0)
318       memcpy(blob.data+currpos, msgUnit->content, msgUnit->contentLen);
319    /* currpos += msgUnit->contentLen; */
320 
321    return blob;
322 }
323 
324 /**
325  * Creates a raw blob to push over a socket as described in protocol.socket
326  * @param msgUnitArr An array of messages
327  * @param debug Set to true if you wish debugging output to stdout
328  * @see http://www.xmlblaster.org/xmlBlaster/doc/requirements/protocol.socket.html
329  * @return The raw 'serialized' MsgUnitArr as a char*, the caller needs to free() it.
330  */
331 Dll_Export BlobHolder encodeMsgUnitArr(MsgUnitArr *msgUnitArr, bool debug)
332 {
333    size_t i;
334    size_t currpos = 0;
335 
336    BlobHolder blob;
337    memset(&blob, 0, sizeof(BlobHolder));
338 
339    if (msgUnitArr == 0) {
340       if (debug) printf("[xmlBlasterSocket] ERROR Invalid msgUnitArr=NULL in encodeMsgUnitArr()\n");
341       return blob;
342    }
343 
344    /* First calculate total length to allocate */
345    for (i=0; i<msgUnitArr->len; i++) {
346       MsgUnit* msgUnit = &msgUnitArr->msgUnitArr[i];
347       size_t qosLen=0, keyLen=0;
348       enum { SIZE = 126 };
349       char contentLenStr[SIZE];
350 
351       if (msgUnit->content == 0)
352          msgUnit->contentLen = 0;
353       snprintf0(contentLenStr, SIZE, "%ld", (long)msgUnit->contentLen);
354 
355       if (msgUnit->qos != 0)
356          qosLen = strlen(msgUnit->qos);
357 
358       if (msgUnit->key != 0)
359          keyLen = strlen(msgUnit->key);
360 
361       blob.dataLen += qosLen + 1 + keyLen + 1 + strlen(contentLenStr) + 1 + msgUnit->contentLen;
362    }
363 
364    blob.data = (char *)malloc(blob.dataLen);
365 
366    /* Now dump the message ... */
367    for (i=0; i<msgUnitArr->len; i++) {
368       MsgUnit* msgUnit = &msgUnitArr->msgUnitArr[i];
369       size_t qosLen=0, keyLen=0, contentLenStrLen=0;
370       enum { SIZE = 126 };
371       char contentLenStr[SIZE];
372 
373       if (msgUnit->content == 0)
374          msgUnit->contentLen = 0;
375       snprintf0(contentLenStr, SIZE, "%ld", (long)msgUnit->contentLen);
376       contentLenStrLen = strlen(contentLenStr);
377 
378       if (msgUnit->qos != 0) {
379          qosLen = strlen(msgUnit->qos);
380          memcpy(blob.data+currpos, msgUnit->qos, qosLen+1); /* inclusive '\0' */
381       }
382       else
383          *(blob.data+currpos) = 0;
384       currpos += qosLen+1;
385 
386       if (msgUnit->key != 0) {
387          keyLen = strlen(msgUnit->key);
388          memcpy(blob.data+currpos, msgUnit->key, keyLen+1); /* inclusive '\0' */
389       }
390       else
391          *(blob.data+currpos) = 0;
392       currpos += keyLen+1;
393 
394       memcpy(blob.data+currpos, contentLenStr, contentLenStrLen+1); /* inclusive '\0' */
395       currpos += contentLenStrLen+1;
396 
397       if (msgUnit->content != 0)
398          memcpy(blob.data+currpos, msgUnit->content, msgUnit->contentLen);
399       currpos += msgUnit->contentLen;
400    }
401    return blob;
402 }
403 
404 char *encodeSocketMessage(
405               enum XMLBLASTER_MSG_TYPE_ENUM msgType,
406               const char * const requestId,
407               const char * const methodName,
408               const char * const secretSessionId,
409               const char *data,
410               size_t dataLen,
411               bool debug,
412               size_t *rawMsgLen)
413 {
414    char *rawMsg = (char *)0;
415    char *rawMsgStr;
416    size_t currpos = 0;
417    enum { SIZE = 256 };
418    char tmp[SIZE];
419    size_t lenUnzipped = dataLen;
420    enum { SIZEF = 56 };
421    char lenFormatStr[56]; /* = "%10.d"; */
422    char lenStr[MSG_LEN_FIELD_LEN+1];
423 
424    if (data == 0) {
425       data = "";
426       dataLen = 0;
427       lenUnzipped = 0;
428    }
429 
430    rawMsg = (char *)calloc(50 + MAX_SESSIONID_LEN + MAX_METHODNAME_LEN + dataLen, sizeof(char));
431 
432    *(rawMsg+MSG_FLAG_POS_TYPE) = (char)msgType;   /* e.g. MSG_TYPE_INVOKE */
433    *(rawMsg+MSG_FLAG_POS_VERSION) = XMLBLASTER_SOCKET_VERSION;
434 
435    currpos = MSG_POS_REQESTID;
436    if (requestId == 0) printf("*** assert: xmlBlasterSocket.c requestId is NULL!\n");
437    memcpy(rawMsg+currpos, requestId, strlen(requestId)+1); /* inclusive '\0' */
438    currpos += strlen(requestId)+1;
439 
440    if (methodName == 0) printf("*** assert: xmlBlasterSocket.c methodName is NULL!\n");
441    memcpy(rawMsg+currpos, methodName, strlen(methodName)+1); /* inclusive '\0' */
442    currpos += strlen(methodName)+1;
443 
444    if (secretSessionId == 0) printf("*** assert: xmlBlasterSocket.c secretSessionId is NULL!\n");
445    memcpy(rawMsg+currpos, secretSessionId, strlen(secretSessionId)+1); /* inclusive '\0' */
446    currpos += strlen(secretSessionId)+1;
447 
448    snprintf0(tmp, SIZE, "%lu", (unsigned long)lenUnzipped);
449    memcpy(rawMsg+currpos, tmp, strlen(tmp)+1); /* inclusive '\0' */
450    currpos += strlen(tmp)+1;
451 
452    if (data == 0) printf("*** assert: xmlBlasterSocket.c data is NULL!\n");
453    memcpy(rawMsg+currpos, data, dataLen);      /* add the msgUnit data */
454    *rawMsgLen = currpos+dataLen;
455 
456    snprintf0(lenFormatStr, SIZEF, "%%%d.d", MSG_LEN_FIELD_LEN);
457    snprintf0(lenStr, MSG_LEN_FIELD_LEN+1, lenFormatStr, *rawMsgLen);
458    memcpy(rawMsg, lenStr, MSG_LEN_FIELD_LEN);
459 
460    if (debug) {
461       rawMsgStr = toReadableDump(rawMsg, *rawMsgLen);
462       printf("[xmlBlasterSocket] Sending now %lu bytes -> '%s'\n", (unsigned long)*rawMsgLen, rawMsgStr);
463       free(rawMsgStr);
464    }
465 
466    return rawMsg;
467 }
468 
469 /**
470  * Read a message from the given socket.
471  * This method blocks until data arrives.
472  *
473  * @param xmlBlasterSocket The socket to read data from (needs to be valid)
474  * @param fpHolder Struct containing the function pointer which access the socket to read from (if necessary decompressing on the fly)
475  * @param socketDataHolder The struct to put the parsed message into (needs to be allocated by you or on your stack)
476  * @param exception The struct to put exceptions into (needs to be allocated by you or to be on your stack)
477  * @param stopP The *stopP may change to 'true' during receiv() blocking
478  * @param udp true if it is a UDP connection
479  * @param debug Set to true to have debugging output on console
480  * @return true: A messages is parsed and put into your socketDataHolder,
481  *         you need to free(socketDataHolder->data) after working with it.
482  *         Please check socketDataHolder->type if it is an exception.
483  *         false: The socket is closed (EOF)
484  */
485 bool parseSocketData(int xmlBlasterSocket, const XmlBlasterReadFromSocketFuncHolder *fpHolder,
486        SocketDataHolder *socketDataHolder, XmlBlasterException *exception, bool *stopP, bool udp, bool debug)
487 {
488    char msgLenPtr[MSG_LEN_FIELD_LEN+1];
489    char *rawMsg = 0;
490    char tmpPtr[256];
491    ssize_t numRead;
492    size_t currPos = 0;
493    unsigned long msgLenL; /* to have 64 bit portable sscanf */
494 
495    char packet[MAX_PACKET_SIZE];
496    /* initialize */
497    memset(msgLenPtr, 0, MSG_LEN_FIELD_LEN+1);
498    memset(socketDataHolder, 0, sizeof(SocketDataHolder));
499    memset(exception, 0, sizeof(XmlBlasterException));
500    exception->remote = false;
501 
502    if (debug) printf("[xmlBlasterSocket] Blocking now for %s callback messages ...\n", (udp) ? "udp" : "tcp");
503    if (udp)
504       numRead = recv(xmlBlasterSocket, packet, MAX_PACKET_SIZE, 0);
505    else
506       /* read the first 10 bytes to determine the length */
507       numRead = fpHolder->readFromSocketFuncP(fpHolder->userP, xmlBlasterSocket, msgLenPtr, MSG_LEN_FIELD_LEN, fpHolder->numReadFuncP, fpHolder->numReadUserP);
508    if (numRead <= 0 || *stopP == true) {
509       return false; /* EOF on socket */
510    }
511    if ((!udp && numRead != MSG_LEN_FIELD_LEN) ||
512        ( udp && numRead < MSG_LEN_FIELD_LEN)) {
513       strncpy0(exception->errorCode, "user.connect", XMLBLASTEREXCEPTION_ERRORCODE_LEN);
514       snprintf0(exception->message, EXCEPTIONSTRUCT_MESSAGE_LEN, "[xmlBlasterSocket] ERROR Received numRead=%ld header bytes but expected %d", (long)numRead, MSG_LEN_FIELD_LEN);
515       if (debug) { printf("%s", exception->message); printf("\n"); }
516       return true;
517    }
518    if (udp) {
519       memcpy(msgLenPtr,  packet, MSG_LEN_FIELD_LEN);
520    }
521    *(msgLenPtr + MSG_LEN_FIELD_LEN) = 0;
522    trim(msgLenPtr);
523    if (strToULong(&msgLenL, msgLenPtr) == false) {
524       strncpy0(exception->errorCode, "user.connect", XMLBLASTEREXCEPTION_ERRORCODE_LEN);
525       snprintf0(exception->message, EXCEPTIONSTRUCT_MESSAGE_LEN,
526               "[xmlBlasterSocket] ERROR Received numRead=%ld header bytes with invalid message length='%s'",
527               (long)numRead, msgLenPtr);
528       if (debug) { printf("%s", exception->message); printf("\n"); }
529       return true;
530    }
531    socketDataHolder->msgLen = (size_t)msgLenL;
532    if (debug) printf("[xmlBlasterSocket] Receiving message of size %lu ...\n", (unsigned long)socketDataHolder->msgLen);
533 
534    if (socketDataHolder->msgLen <= MSG_LEN_FIELD_LEN || socketDataHolder->msgLen > MAX_MSG_LEN) {
535       strncpy0(exception->errorCode, "user.connect", XMLBLASTEREXCEPTION_ERRORCODE_LEN);
536       snprintf0(exception->message, EXCEPTIONSTRUCT_MESSAGE_LEN,
537               "[xmlBlasterSocket] ERROR Received numRead=%ld header bytes with invalid message length='%s' parsed to '%ld'",
538               (long)numRead, msgLenPtr, (long)socketDataHolder->msgLen);
539       if (debug) { printf("%s", exception->message); printf("\n"); }
540       return true;
541    }
542 
543    /* read the complete message */
544    rawMsg = (char *)calloc(socketDataHolder->msgLen, sizeof(char));
545    memcpy(rawMsg, msgLenPtr, MSG_LEN_FIELD_LEN);
546    if (udp) {
547       memcpy(rawMsg+MSG_LEN_FIELD_LEN, packet+MSG_LEN_FIELD_LEN, socketDataHolder->msgLen-MSG_LEN_FIELD_LEN);
548       numRead -= MSG_LEN_FIELD_LEN;
549    }
550    else
551       numRead = fpHolder->readFromSocketFuncP(fpHolder->userP, xmlBlasterSocket, rawMsg+MSG_LEN_FIELD_LEN,
552                           (size_t)socketDataHolder->msgLen-MSG_LEN_FIELD_LEN, fpHolder->numReadFuncP, fpHolder->numReadUserP);
553    if (numRead <= 0 || *stopP == true) {
554       free(rawMsg);
555       return false; /* EOF on socket */
556    }
557    if ((size_t)numRead != (socketDataHolder->msgLen-MSG_LEN_FIELD_LEN)) {
558       strncpy0(exception->errorCode, "user.response", XMLBLASTEREXCEPTION_ERRORCODE_LEN);
559       snprintf0(exception->message, EXCEPTIONSTRUCT_MESSAGE_LEN, "[xmlBlasterSocket] ERROR Received numRead=%ld message bytes but expected %lu", (long)numRead, (unsigned long)(socketDataHolder->msgLen-MSG_LEN_FIELD_LEN));
560       if (debug) { printf("%s", exception->message); printf("\n"); }
561       free(rawMsg);
562       return true;
563    }
564 
565    if (debug) {
566       char *rawMsgStr = toReadableDump(rawMsg, socketDataHolder->msgLen);
567       printf("[xmlBlasterSocket] Read %lu bytes from socket -> '%s'\n", (unsigned long)socketDataHolder->msgLen, rawMsgStr);
568       free(rawMsgStr);
569    }
570 
571    /* if (debug) {
572       char *tmp = toReadableDump(rawMsg, socketDataHolder->msgLen);
573       printf("[xmlBlasterSocket] Read %u bytes from socket\n%s\n", socketDataHolder->msgLen, tmp);
574       free(tmp);
575    }*/
576 
577    socketDataHolder->type = *(rawMsg+MSG_FLAG_POS_TYPE);
578    if (socketDataHolder->type != MSG_TYPE_INVOKE &&
579        socketDataHolder->type != MSG_TYPE_RESPONSE &&
580        socketDataHolder->type != MSG_TYPE_EXCEPTION) {
581       strncpy0(exception->errorCode, "user.response", XMLBLASTEREXCEPTION_ERRORCODE_LEN);
582       snprintf0(exception->message, EXCEPTIONSTRUCT_MESSAGE_LEN, "[xmlBlasterSocket] ERROR Received response message of type=%c", socketDataHolder->type);
583       if (debug) { printf("%s", exception->message); printf("\n"); }
584       free(rawMsg);
585       return true;
586    }
587 
588    socketDataHolder->version = *(rawMsg+MSG_FLAG_POS_VERSION);
589    if (socketDataHolder->version != XMLBLASTER_SOCKET_VERSION) {
590       strncpy0(exception->errorCode, "user.response", XMLBLASTEREXCEPTION_ERRORCODE_LEN);
591       snprintf0(exception->message, EXCEPTIONSTRUCT_MESSAGE_LEN, "[xmlBlasterSocket] ERROR Received response message of unsupported version=%c", socketDataHolder->version);
592       if (debug) { printf("%s", exception->message); printf("\n"); }
593       free(rawMsg);
594       return true;
595    }
596 
597 
598    currPos = MSG_POS_REQESTID;
599 
600    strncpy0(socketDataHolder->requestId, rawMsg+currPos, MAX_REQUESTID_LEN);
601    currPos += strlen(socketDataHolder->requestId)+1;
602 
603    strncpy0(socketDataHolder->methodName, rawMsg+currPos, MAX_METHODNAME_LEN);
604    currPos += strlen(socketDataHolder->methodName)+1;
605 
606    strncpy0(socketDataHolder->secretSessionId, rawMsg+currPos, MAX_SESSIONID_LEN);
607    currPos += strlen(socketDataHolder->secretSessionId)+1;
608 
609    strncpy0(tmpPtr, rawMsg+currPos, 256);
610    currPos += strlen(tmpPtr)+1;
611    trim(tmpPtr);
612    socketDataHolder->dataLenUncompressed = 0;
613    msgLenL = 0;
614    if (strlen(tmpPtr) > 0 && strToULong(&msgLenL, tmpPtr) != 1) {
615       printf("[xmlBlasterSocket] WARN uncompressed data length '%s' is invalid, we continue nevertheless\n", tmpPtr);
616    }
617    else {
618       socketDataHolder->dataLenUncompressed = (size_t)msgLenL;
619    }
620 
621    /* Read the payload */
622    socketDataHolder->blob.dataLen = socketDataHolder->msgLen - currPos;
623    if (socketDataHolder->blob.dataLen > 0) {
624       socketDataHolder->blob.data = (char *)malloc(socketDataHolder->blob.dataLen * sizeof(char));
625       memcpy(socketDataHolder->blob.data, rawMsg+currPos, socketDataHolder->blob.dataLen);
626    }
627    else {
628       /*
629       socketDataHolder->blob.dataLen = 6;
630       socketDataHolder->blob.data = strcpyAlloc("<qos/>");
631       */
632       /*
633       Allow empty message for example for get() returns with no match
634       socketDataHolder->blob.dataLen = 1;
635       socketDataHolder->blob.data = (char *)malloc(1);
636       *socketDataHolder->blob.data = 0;
637       */
638    }
639 
640    free(rawMsg);
641    rawMsg = 0;
642    return true;
643 }
644 
645 /**
646  * The blob data is copied into the given exception object.
647  * Note: exception->remote is always set to true (assuming a remote blob)
648  */
649 void convertToXmlBlasterException(const XmlBlasterBlob *blob, XmlBlasterException *exception, bool debug)
650 {
651    size_t currpos = 0;
652    size_t len;
653    /* initializeXmlBlasterException(exception); */
654    exception->remote = true;
655    strncpy0(exception->errorCode, blob->data+currpos, XMLBLASTEREXCEPTION_ERRORCODE_LEN);
656    currpos += strlen(exception->errorCode) + 1;
657    len = ((blob->dataLen-currpos) > XMLBLASTEREXCEPTION_MESSAGE_LEN) ? XMLBLASTEREXCEPTION_MESSAGE_LEN : (blob->dataLen-currpos);
658    strncpy0(exception->message, blob->data+currpos, len);
659    trim(exception->message);
660    if (debug) printf("[xmlBlasterSocket] Converted to XmlBlasterException\n");
661 }
662 
663 /**
664  * The given exception is dumped into the blob data.
665  * @param blob The encoded exception, you need to free the blob struct yourself after usage with
666  *             freeBlobHolderContent(&blob);
667  * @param exception The given exception struct
668  * @param debug Print output to stdout
669  */
670 void encodeXmlBlasterException(XmlBlasterBlob *blob, const XmlBlasterException *exception, bool debug)
671 {
672    MsgUnit msgUnit;
673    BlobHolder b;
674 
675    memset(&msgUnit, 0, sizeof(MsgUnit));
676    msgUnit.qos = exception->errorCode;
677    msgUnit.key = exception->message;
678 
679    b = encodeMsgUnit(&msgUnit, debug);
680    blob->data = b.data;
681    blob->dataLen = b.dataLen;
682    if (debug) printf("[xmlBlasterSocket] Converted XmlBlasterException to SOCKET blob\n");
683 }
684 
685 /**
686  * Parses the QoS XML string array returned by erase() and unSubscribe()
687  * @return The returned status QoS, never null, needs to be freed with freeQosArr() after usage.
688  */
689 QosArr *parseQosArr(size_t dataLen, char *data)
690 {
691    size_t ii;
692    MsgUnitArr *msgUnitArr = parseMsgUnitArr(dataLen, data);
693    QosArr* qosArr = (QosArr *)calloc(1, sizeof(QosArr));
694    qosArr->len = msgUnitArr->len;
695    qosArr->qosArr = (const char **)calloc(qosArr->len, sizeof(const char *));
696    for (ii=0; ii<msgUnitArr->len; ii++) {
697       qosArr->qosArr[ii] = strcpyAlloc(msgUnitArr->msgUnitArr[ii].qos);
698    }
699    freeMsgUnitArr(msgUnitArr);
700    return qosArr;
701 }
702 
703 /**
704  * Parses the userData part of a raw socket message and fills an array
705  * of MsgUnit structs.
706  * @return The messages (never NULL), you need to free them after usage with freeMsgUnitArr(MsgUnitArr *)
707  */
708 Dll_Export MsgUnitArr *parseMsgUnitArr(size_t dataLen, char *data)
709 {
710    MsgUnitArr *msgUnitArr = (MsgUnitArr *)calloc(1, sizeof(MsgUnitArr));
711    size_t currpos = 0;
712    uint32_t currIndex = 0;
713    enum { SIZE = 56 };
714    msgUnitArr->isOneway = false;
715    if (dataLen <= 0) {
716       return msgUnitArr; /* Empty messageUnit array, only a first \0 for the qos */
717    }
718    msgUnitArr->len = 10;
719    msgUnitArr->msgUnitArr = (MsgUnit *)calloc(msgUnitArr->len, sizeof(MsgUnit));
720    while (currpos < dataLen) {
721       char ptr[SIZE];
722 
723       if (currIndex >= msgUnitArr->len) {
724          msgUnitArr->len += 10;
725          msgUnitArr->msgUnitArr = (MsgUnit *)realloc(msgUnitArr->msgUnitArr, msgUnitArr->len * sizeof(MsgUnit));
726       }
727 
728       {
729          unsigned long msgLenL; /* to have 64 bit portable sscanf */
730          MsgUnit *msgUnit = &msgUnitArr->msgUnitArr[currIndex++];
731          memset(msgUnit, 0, sizeof(MsgUnit));
732 
733          /* read QoS */
734          msgUnit->qos = strcpyAlloc(data+currpos);
735          currpos += strlen(msgUnit->qos)+1;
736 
737          /* read key */
738          if (currpos < dataLen) {
739             if (strlen(data+currpos) > 0) {
740                msgUnit->key = strcpyAlloc(data+currpos);
741                currpos += strlen(msgUnit->key)+1;
742             }
743             else {
744                currpos++;
745             }
746          }
747 
748          /* read content */
749          if (currpos < dataLen) {
750             char *tmp;
751             strncpy0(ptr, data+currpos, SIZE);
752             currpos += strlen(ptr)+1;
753             trim(ptr);
754             msgLenL = 0;
755             if (strToULong(&msgLenL, ptr) != 1) {
756                printf("[xmlBlasterSocket] WARN MsgUnit content length '%s' is invalid, we continue nevertheless\n", ptr);
757             }
758             msgUnit->contentLen = (size_t)msgLenL;
759 
760             tmp = (char *)malloc(msgUnit->contentLen * sizeof(char));
761             memcpy(tmp, data+currpos, msgUnit->contentLen);
762             msgUnit->content = tmp;
763             currpos += msgUnit->contentLen;
764          }
765       }
766    }
767 
768    if (currIndex == 0) {
769       free(msgUnitArr->msgUnitArr);
770       msgUnitArr->len = 0;
771    }
772    else if (currIndex < msgUnitArr->len) {
773       msgUnitArr->msgUnitArr = (MsgUnit *)realloc(msgUnitArr->msgUnitArr, currIndex * sizeof(MsgUnit));
774       msgUnitArr->len = currIndex;
775    }
776 
777    return msgUnitArr;
778 }


syntax highlighted by Code2HTML, v. 0.9.1