00001 /*---------------------------------------------------------------------------- 00002 Name: xmlBlaster/src/c/util/msgUtil.c 00003 Project: xmlBlaster.org 00004 Copyright: xmlBlaster.org, see xmlBlaster-LICENSE file 00005 Comment: Contains helper functions for string and message manipulation 00006 Compile: gcc -Wall -g -o msgUtil msgUtil.c -DMSG_UTIL_MAIN -I.. 00007 Testsuite: xmlBlaster/testsuite/src/c/TestUtil.c 00008 Author: "Marcel Ruff" <xmlBlaster@marcelruff.info> 00009 -----------------------------------------------------------------------------*/ 00010 00011 #include <stdio.h> 00012 #include <stdlib.h> 00013 #include <string.h> 00014 #include <assert.h> 00015 #include "helper.h" 00016 #include "msgUtil.h" 00017 00018 #ifdef _ENABLE_STACK_TRACE_ 00019 # include <execinfo.h> 00020 #endif 00021 00022 #ifdef _WINDOWS 00023 # include <Winsock2.h> /* gethostbyname() */ 00024 #else 00025 # include <netdb.h> /* gethostbyname_re() */ 00026 # include <errno.h> /* gethostbyname_re() */ 00027 #endif 00028 00029 #if !defined(XMLBLASTER_NO_RCSID) 00030 /* 00031 Add the exact version of the C client library, this is for examination 00032 with for example the UNIX 'strings' command only. 00033 If it makes problem just set -DXMLBLASTER_NO_RCSID 00034 */ 00035 #if defined(__GNUC__) || defined(__ICC) 00036 /* To support query state with 'ident libxmlBlasterClientC.so' or 'what libxmlBlasterClientC.so' 00037 or 'strings libxmlBlasterClientC.so | grep msgUtil.c' */ 00038 static const char *rcsid_GlobalCpp __attribute__ ((unused)) = "@(#) $Id: msgUtil.c 16646 2007-12-03 15:35:54Z ruff $ xmlBlaster @version@ #@revision.number@"; 00039 #elif defined(__SUNPRO_CC) 00040 static const char *rcsid_GlobalCpp = "@(#) $Id: msgUtil.c 16646 2007-12-03 15:35:54Z ruff $ xmlBlaster @version@ #@revision.number@"; 00041 #endif 00042 #endif 00043 00047 Dll_Export const char *getXmlBlasterVersion(void) 00048 { 00049 /* Is replaced by xmlBlaster/build.xml ant task */ 00050 static const char *p1 = "@version@"; 00051 static const char *p2 = "@version@ #@revision.number@"; 00052 if (strstr(p2, "@") == 0 && strstr(p2, "${") == 0) { /* Verify that subversion replacement worked fine */ 00053 return p2; 00054 } 00055 if (strstr(p1, "@") == 0) { /* Verify that version replacement worked fine */ 00056 return p1; 00057 } 00058 return "1.6.2"; 00059 } 00060 00072 Dll_Export void xmlBlasterFree(char *p) 00073 { 00074 if (p != (char *)0) { 00075 free(p); 00076 } 00077 } 00078 00083 Dll_Export void freeQosArr(QosArr *qosArr) 00084 { 00085 size_t i; 00086 if (qosArr == (QosArr *)0) return; 00087 for (i=0; i<qosArr->len; i++) { 00088 free((char *)qosArr->qosArr[i]); 00089 } 00090 free((char *)qosArr->qosArr); 00091 qosArr->len = 0; 00092 free(qosArr); 00093 } 00094 00099 Dll_Export void freeMsgUnitArr(MsgUnitArr *msgUnitArr) 00100 { 00101 if (msgUnitArr == (MsgUnitArr *)0) return; 00102 freeMsgUnitArrInternal(msgUnitArr); 00103 free(msgUnitArr); 00104 } 00105 00110 Dll_Export void freeMsgUnitArrInternal(MsgUnitArr *msgUnitArr) 00111 { 00112 size_t i; 00113 if (msgUnitArr == (MsgUnitArr *)0) return; 00114 for (i=0; i<msgUnitArr->len; i++) { 00115 freeMsgUnitData(&msgUnitArr->msgUnitArr[i]); 00116 } 00117 free(msgUnitArr->msgUnitArr); 00118 msgUnitArr->len = 0; 00119 } 00120 00124 Dll_Export void freeMsgUnitData(MsgUnit *msgUnit) 00125 { 00126 if (msgUnit == (MsgUnit *)0) return; 00127 if (msgUnit->key != 0) { 00128 free((char *)msgUnit->key); 00129 msgUnit->key = 0; 00130 } 00131 if (msgUnit->content != 0) { 00132 free((char *)msgUnit->content); 00133 msgUnit->content = 0; 00134 } 00135 msgUnit->contentLen = 0; 00136 if (msgUnit->qos != 0) { 00137 free((char *)msgUnit->qos); 00138 msgUnit->qos = 0; 00139 } 00140 if (msgUnit->responseQos != 0) { 00141 free((char *)msgUnit->responseQos); 00142 msgUnit->responseQos = 0; 00143 } 00144 /* free(msgUnit); -> not in this case, as the containing array has not allocated us separately */ 00145 } 00146 00150 Dll_Export void freeMsgUnit(MsgUnit *msgUnit) 00151 { 00152 if (msgUnit == (MsgUnit *)0) return; 00153 freeMsgUnitData(msgUnit); 00154 free(msgUnit); 00155 } 00156 00165 Dll_Export char *messageUnitToXmlLimited(MsgUnit *msg, int maxContentDumpLen) 00166 { 00167 if (msg->key == 0 && msg->contentLen < 1) { 00168 return strcpyAlloc(msg->qos); 00169 } 00170 else if (msg->contentLen < 1) { 00171 char *xml = strcpyAlloc(msg->key); 00172 if (xml == 0) return 0; 00173 return strcatAlloc(&xml, msg->qos); 00174 } 00175 else { 00176 char *contentStr = strFromBlobAlloc(msg->content, msg->contentLen); 00177 size_t len = 200 + strlen(msg->key) + msg->contentLen + strlen(msg->qos); 00178 char *xml = (char *)calloc(len, sizeof(char)); 00179 if (xml == 0) { 00180 free(contentStr); 00181 return 0; 00182 } 00183 if (maxContentDumpLen == 0) 00184 *contentStr = 0; 00185 else if (maxContentDumpLen > 0 && msg->contentLen > 5 && (size_t)maxContentDumpLen < (msg->contentLen-5)) 00186 strncpy0(contentStr+maxContentDumpLen, " ...", 5); 00187 SNPRINTF(xml, len, "%s\n <content size='%lu'><![CDATA[%s]]></content>%s", 00188 msg->key, (unsigned long)msg->contentLen, contentStr, msg->qos); 00189 free(contentStr); 00190 return xml; 00191 } 00192 } 00193 00199 Dll_Export char *messageUnitToXml(MsgUnit *msg) 00200 { 00201 return messageUnitToXmlLimited(msg, -1); 00202 } 00203 00207 Dll_Export _INLINE_FUNC void initializeXmlBlasterException(XmlBlasterException *xmlBlasterException) 00208 { 00209 xmlBlasterException->remote = false; 00210 *xmlBlasterException->errorCode = (char)0; 00211 *xmlBlasterException->message = (char)0; 00212 } 00213 00214 00215 /* a local version of the 6 argument call to gethostbyname_r 00216 this is copied from http://www.cygwin.com/ml/cygwin/2004-04/msg00532.html 00217 thanks to Enzo Michelangeli for this 00218 */ 00219 #if defined(__FreeBSD__) || defined(__MacOSX__) 00220 /* this should actually work for other platforms... so long as they support pthreads */ 00221 /* since this is a 6 arg format... just define that here */ 00222 #define HAVE_FUNC_GETHOSTBYNAME_R_6 00223 /* duh? ERANGE value copied from web... */ 00224 #define ERANGE 34 00225 int gethostbyname_r (const char *name, 00226 struct hostent *ret, 00227 char *buf, 00228 size_t buflen, 00229 struct hostent **result, 00230 int *h_errnop) { 00231 00232 int hsave; 00233 struct hostent *ph; 00234 static pthread_mutex_t __mutex = PTHREAD_MUTEX_INITIALIZER; 00235 pthread_mutex_lock(&__mutex); /* begin critical area */ 00236 hsave = h_errno; 00237 ph = gethostbyname(name); 00238 *h_errnop = h_errno; /* copy h_errno to *h_herrnop */ 00239 00240 if (ph == NULL) { 00241 *result = NULL; 00242 } else { 00243 char **p, **q; 00244 char *pbuf; 00245 int nbytes=0; 00246 int naddr=0, naliases=0; 00247 /* determine if we have enough space in buf */ 00248 00249 /* count how many addresses */ 00250 for (p = ph->h_addr_list; *p != 0; p++) { 00251 nbytes += ph->h_length; /* addresses */ 00252 nbytes += sizeof(*p); /* pointers */ 00253 naddr++; 00254 } 00255 nbytes += sizeof(*p); /* one more for the terminating NULL */ 00256 00257 /* count how many aliases, and total length of strings */ 00258 00259 for (p = ph->h_aliases; *p != 0; p++) { 00260 nbytes += (strlen(*p)+1); /* aliases */ 00261 nbytes += sizeof(*p); /* pointers */ 00262 naliases++; 00263 } 00264 nbytes += sizeof(*p); /* one more for the terminating NULL */ 00265 00266 /* here nbytes is the number of bytes required in buffer */ 00267 /* as a terminator must be there, the minimum value is ph->h_length */ 00268 if(nbytes > buflen) { 00269 *result = NULL; 00270 pthread_mutex_unlock(&__mutex); /* end critical area */ 00271 return ERANGE; /* not enough space in buf!! */ 00272 } 00273 00274 /* There is enough space. Now we need to do a deep copy! */ 00275 /* Allocation in buffer: 00276 from [0] to [(naddr-1) * sizeof(*p)]: 00277 pointers to addresses 00278 at [naddr * sizeof(*p)]: 00279 NULL 00280 from [(naddr+1) * sizeof(*p)] to [(naddr+naliases) * sizeof(*p)] : 00281 pointers to aliases 00282 at [(naddr+naliases+1) * sizeof(*p)]: 00283 NULL 00284 then naddr addresses (fixed length), and naliases aliases (asciiz). 00285 */ 00286 00287 *ret = *ph; /* copy whole structure (not its address!) */ 00288 00289 /* copy addresses */ 00290 q = (char **)buf; /* pointer to pointers area (type: char **) */ 00291 ret->h_addr_list = q; /* update pointer to address list */ 00292 pbuf = buf + ((naddr+naliases+2)*sizeof(*p)); /* skip that area */ 00293 for (p = ph->h_addr_list; *p != 0; p++) { 00294 memcpy(pbuf, *p, ph->h_length); /* copy address bytes */ 00295 *q++ = pbuf; /* the pointer is the one inside buf... */ 00296 pbuf += ph->h_length; /* advance pbuf */ 00297 } 00298 *q++ = NULL; /* address list terminator */ 00299 00300 /* copy aliases */ 00301 00302 ret->h_aliases = q; /* update pointer to aliases list */ 00303 for (p = ph->h_aliases; *p != 0; p++) { 00304 strcpy(pbuf, *p); /* copy alias strings */ 00305 *q++ = pbuf; /* the pointer is the one inside buf... */ 00306 pbuf += strlen(*p); /* advance pbuf */ 00307 *pbuf++ = 0; /* string terminator */ 00308 } 00309 *q++ = NULL; /* terminator */ 00310 00311 strcpy(pbuf, ph->h_name); /* copy alias strings */ 00312 ret->h_name = pbuf; 00313 pbuf += strlen(ph->h_name); /* advance pbuf */ 00314 *pbuf++ = 0; /* string terminator */ 00315 00316 *result = ret; /* and let *result point to structure */ 00317 00318 } 00319 h_errno = hsave; /* restore h_errno */ 00320 00321 pthread_mutex_unlock(&__mutex); /* end critical area */ 00322 00323 return (*result == NULL); 00324 00325 } 00326 00327 #endif /* defined(__FreeBSD__) || defined(__MacOSX__) */ 00328 00329 #if defined(WINCE) 00330 /* Ws2tcpip.h(550) : error C2632: 'int' followed by 'int' is illegal 00331 These errors are caused by redefinition in WinInet.h. */ 00332 /*#include <Ws2tcpip.h>*/ /* for getaddrinfo() only */ 00333 #endif 00334 00340 Dll_Export struct hostent * gethostbyname_re (const char *host,struct hostent *hostbuf, 00341 char **tmphstbuf,size_t *hstbuflen, 00342 char errP[MAX_ERRNO_LEN]) 00343 { 00344 #if defined(_WINDOWS_FUTURE) 00345 /* See http://www.hmug.org/man/3/getaddrinfo.html for an example */ 00346 /* #include Ws2tcpip.h 00347 typedef struct addrinfo { 00348 int ai_flags; 00349 int ai_family; 00350 int ai_socktype; 00351 int ai_protocol; 00352 size_t ai_addrlen; 00353 char* ai_canonname; 00354 struct sockaddr* ai_addr; 00355 struct addrinfo* ai_next; 00356 } addrinfo; 00357 00358 struct sockaddr_in { 00359 short sin_family; 00360 u_short sin_port; 00361 struct in_addr sin_addr; 00362 char sin_zero[8]; 00363 }; 00364 */ 00365 # ifdef SOME_CLIENT_EXAMPLE 00366 struct addrinfo hints, *res, *res0; 00367 int error; 00368 int s; 00369 const char *cause = NULL; 00370 const char* servname = "7609"; /* or "http" */ 00371 memset(&hints, 0, sizeof(hints)); 00372 hints.ai_family = PF_UNSPEC; 00373 hints.ai_socktype = SOCK_STREAM; 00374 error = getaddrinfo(host, servname, &hints, &res0); 00375 if (error) { 00376 errx(1, "%s", gai_strerror(error)); 00377 /*NOTREACHED*/ 00378 } 00379 s = -1; 00380 cause = "no addresses"; 00381 errno = EADDRNOTAVAIL; 00382 for (res = res0; res; res = res->ai_next) { 00383 s = socket(res->ai_family, res->ai_socktype, 00384 res->ai_protocol); 00385 if (s < 0) { 00386 cause = "socket"; 00387 continue; 00388 } 00389 if (connect(s, res->ai_addr, res->ai_addrlen) < 0) { 00390 cause = "connect"; 00391 close(s); 00392 s = -1; 00393 continue; 00394 } 00395 break; /* okay we got one */ 00396 } 00397 if (s < 0) { 00398 err(1, cause); 00399 /*NOTREACHED*/ 00400 } 00401 freeaddrinfo(res0); 00402 # endif /* SOME_CLIENT_EXAMPLE */ 00403 # ifdef SOME_SERVER_EXAMPLE 00404 /* The following example tries to open a wildcard listening socket onto ser- 00405 vice ``http'', for all the address families available. */ 00406 00407 struct addrinfo hints, *res, *res0; 00408 int error; 00409 int s[MAXSOCK]; 00410 int nsock; 00411 const char* servname = "7609"; /* or "http" */ 00412 const char *cause = NULL; 00413 memset(&hints, 0, sizeof(hints)); 00414 hints.ai_family = PF_UNSPEC; 00415 hints.ai_socktype = SOCK_STREAM; 00416 hints.ai_flags = AI_PASSIVE; 00417 error = getaddrinfo(NULL, servname, &hints, &res0); 00418 if (error) { 00419 errx(1, "%s", gai_strerror(error)); 00420 /*NOTREACHED*/ 00421 } 00422 nsock = 0; 00423 for (res = res0; res && nsock < MAXSOCK; res = res->ai_next) { 00424 s[nsock] = socket(res->ai_family, res->ai_socktype, 00425 res->ai_protocol); 00426 if (s[nsock] < 0) { 00427 cause = "socket"; 00428 continue; 00429 } 00430 if (bind(s[nsock], res->ai_addr, res->ai_addrlen) < 0) { 00431 cause = "bind"; 00432 close(s[nsock]); 00433 continue; 00434 } 00435 if (listen(s[nsock], SOMAXCONN) < 0) { 00436 cause = "listen"; 00437 close(s[nsock]); 00438 continue; 00439 } 00440 nsock++; 00441 } 00442 if (nsock == 0) { 00443 err(1, cause); 00444 /*NOTREACHED*/ 00445 } 00446 freeaddrinfo(res0); 00447 # endif /* SOME_SERVER_EXAMPLE */ 00448 #elif defined(__sun) 00449 struct hostent *hp; 00450 int herr; 00451 00452 if (*hstbuflen == 0) 00453 { 00454 *hstbuflen = 1024; 00455 *tmphstbuf = (char *)malloc (*hstbuflen); 00456 if (*tmphstbuf == 0) return 0; 00457 } 00458 00459 while ((NULL == ( hp = 00460 gethostbyname_r(host,hostbuf,*tmphstbuf,*hstbuflen,&herr))) 00461 && (errno == ERANGE)) 00462 { 00463 /* Enlarge the buffer. */ 00464 *hstbuflen *= 2; 00465 *tmphstbuf = (char *)realloc (*tmphstbuf,*hstbuflen); 00466 if (*tmphstbuf == 0) return 0; 00467 } 00468 return hp; 00469 #elif defined(__alpha) /* OSF1 V5.1 1885 alpha */ 00470 if (*hstbuflen == 0) 00471 { 00472 *hstbuflen = sizeof(struct hostent_data); 00473 *tmphstbuf = (char *)malloc (*hstbuflen); 00474 if (*tmphstbuf == 0) return 0; 00475 } 00476 else if (*hstbuflen < sizeof(struct hostent_data)) 00477 { 00478 *hstbuflen = sizeof(struct hostent_data); 00479 *tmphstbuf = (char *)realloc(*tmphstbuf, *hstbuflen); 00480 if (*tmphstbuf == 0) return 0; 00481 } 00482 memset((void *)(*tmphstbuf),0,*hstbuflen); 00483 00484 if (0 != gethostbyname_r(host,hostbuf,(struct hostent_data *)*tmphstbuf)) { 00485 free(*tmphstbuf); 00486 *tmphstbuf = 0; 00487 return 0; 00488 } 00489 return hostbuf; 00490 #elif defined(WINCE) 00491 /* Header: Winsock2.h. */ 00492 /* Link Library: Ws2.lib. */ 00493 struct hostent* remoteHost; 00494 unsigned int addr; 00495 const char *pp = 0; 00496 hostbuf = 0; /* Do something with unused arguments to avoid compiler warning */ 00497 tmphstbuf = 0; 00498 hstbuflen = 0; 00499 *errP = 0; 00500 WSASetLastError(0); 00501 00502 #if Ws2tcpip_USE 00503 { /* The future preferred way, not yet ready implemented */ 00504 /*host: Pointer to a NULL-terminated string containing a host (node) name or a numeric host address string. The numeric host address string is a dotted-decimal IPv4 address or an IPv6 hexadecimal address.*/ 00505 const char FAR* servname = 0; /* Pointer to a NULL-terminated string containing either a service name or port number. */ 00506 const struct addrinfo hints; /* Pointer to an addrinfo structure that provides hints about the type of socket the caller supports. */ 00507 struct addrinfo FAR* FAR* res; /* out */ 00508 int errorReturn = 0; /* return: This function returns zero when successful. The return of a nonzero Windows Sockets error code indicates failure. */ 00509 memset((char *)&hints, 0, sizeof(struct addrinfo)); 00510 errorReturn = getaddrinfo(host, servname, &hints, res); 00511 } 00512 #endif /*Ws2tcpip_USE*/ 00513 00514 /* If the user input is an alpha name for the host, use gethostbyname() */ 00515 if (isalpha(host[0])) { /* host address is a name */ 00516 remoteHost = gethostbyname(host); /* Not thread safe, returns null on error (use WSAGetLastError() to retrieve reason) */ 00517 pp = "gethostbyname"; 00518 } 00519 else { 00520 /* The gethostbyaddr function has been deprecated by the introduction of the getnameinfo function. */ 00521 /* If not, get host by addr (assume IPv4) e.g. "192.168.1.1" */ 00522 addr = inet_addr(host); 00523 remoteHost = gethostbyaddr((char *) &addr, 4, AF_INET); 00524 /* If an error occurs, it returns a NULL pointer, and a specific error code can be retrieved by calling WSAGetLastError. */ 00525 pp = "gethostbyaddr"; 00526 } 00527 if (remoteHost == 0) { 00528 int err = WSAGetLastError(); /* does not reset the error code, use WSASetLastError(0) to do it */ 00529 /* for error codes see http://msdn2.microsoft.com/en-us/library/ms740668.aspx */ 00530 /*if (WSAGetLastError() == 11001) 00531 printf("Host %s not found\n", host);*/ 00532 /*printf("Host %s not found, WSAGetLastError=%d\n", host, err);*/ 00533 SNPRINTF(errP, MAX_ERRNO_LEN, "%s(%s) not found, WSAGetLastError=%d, see http://msdn2.microsoft.com/en-us/library/ms740668.aspx\n", pp, host, err); 00534 WSASetLastError(0); 00535 return 0; 00536 } 00537 else { 00538 *errP = 0; 00539 return remoteHost; 00540 } 00541 #elif defined(_WINDOWS) 00542 /*Winsock2.h, Ws2_32.lib, Ws2_32.dll*/ 00543 struct hostent* remoteHost; 00544 unsigned int addr; 00545 const char *pp = 0; 00546 hostbuf = 0; /* Do something with unused arguments to avoid compiler warning */ 00547 tmphstbuf = 0; 00548 hstbuflen = 0; 00549 *errP = 0; 00550 WSASetLastError(0); 00551 00552 /* If the user input is an alpha name for the host, use gethostbyname() */ 00553 if (isalpha(host[0])) { /* host address is a name */ 00554 remoteHost = gethostbyname(host); /* Not thread safe */ 00555 pp = "gethostbyname"; 00556 } 00557 else { 00558 /* If not, get host by addr (assume IPv4) e.g. "192.168.1.1" */ 00559 addr = inet_addr(host); 00560 remoteHost = gethostbyaddr((char *) &addr, 4, AF_INET); 00561 pp = "gethostbyaddr"; 00562 } 00563 00564 if (remoteHost == 0) { 00565 int err = WSAGetLastError(); /* does not reset the error code, use WSASetLastError(0) to do it */ 00566 /* for error codes see http://msdn2.microsoft.com/en-us/library/ms740668.aspx */ 00567 /*if (WSAGetLastError() == 11001) 00568 printf("Host %s not found\n", host);*/ 00569 /*printf("Host %s not found, WSAGetLastError=%d\n", host, err);*/ 00570 SNPRINTF(errP, MAX_ERRNO_LEN, "%s(%s) not found, WSAGetLastError=%d, see http://msdn2.microsoft.com/en-us/library/ms740668.aspx\n", pp, host, err); 00571 WSASetLastError(0); 00572 return 0; 00573 } 00574 else { 00575 *errP = 0; 00576 return remoteHost; 00577 } 00578 #else /* HAVE_FUNC_GETHOSTBYNAME_R_6 Linux */ /* defined(__hpux) with gcc 2.8 - 3.4.3 */ 00579 struct hostent *hp=0; 00580 int herr=0,res=0; 00581 00582 assert(tmphstbuf != 0); 00583 00584 if (*hstbuflen == 0) 00585 { 00586 *hstbuflen = 1024; 00587 *tmphstbuf = (char *)calloc (*hstbuflen, sizeof(char)); 00588 if (*tmphstbuf == 0) return 0; 00589 } 00590 00591 while (( res = 00592 gethostbyname_r(host,hostbuf,*tmphstbuf,*hstbuflen,&hp,&herr)) 00593 && (errno == ERANGE)) 00594 { 00595 /* Enlarge the buffer. */ 00596 *hstbuflen *= 2; 00597 *tmphstbuf = (char *)realloc (*tmphstbuf,*hstbuflen); 00598 if (*tmphstbuf == 0) return 0; 00599 } 00600 if (res != 0) { 00601 free(*tmphstbuf); 00602 *tmphstbuf = 0; 00603 return 0; 00604 } 00605 return hp; 00606 #endif 00607 } 00608 00609 # ifdef MSG_UTIL_MAIN 00610 /* On Linux defaults to HAVE_FUNC_GETHOSTBYNAME_R_6: 00611 gcc -g -Wall -o msgUtil msgUtil.c helper.c -I.. -DMSG_UTIL_MAIN=1 00612 */ 00613 int main() 00614 { 00615 struct hostent hostbuf, *hostP = 0; 00616 char *tmphstbuf=0; 00617 size_t hstbuflen=0; 00618 char serverHostName[256]; 00619 strcpy(serverHostName, "localhost"); 00620 hostP = gethostbyname_re(serverHostName, &hostbuf, &tmphstbuf, &hstbuflen); 00621 printf("Hello '%s'\n", hostP->h_name); 00622 return 0; 00623 } 00624 # endif