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