util/msgUtil.c

Go to the documentation of this file.
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