1 /*----------------------------------------------------------------------------
  2 Name:      xmlBlaster/src/c/util/msgUtil.c
  3 Project:   xmlBlaster.org
  4 Copyright: xmlBlaster.org, see xmlBlaster-LICENSE file
  5 Comment:   Contains helper functions for string and message manipulation
  6 Compile:   gcc -Wall -g -o msgUtil msgUtil.c -DMSG_UTIL_MAIN -I..
  7 Testsuite: xmlBlaster/testsuite/src/c/TestUtil.c
  8 Author:    "Marcel Ruff" <xmlBlaster@marcelruff.info>
  9 -----------------------------------------------------------------------------*/
 10 
 11 #include <stdio.h>
 12 #include <stdlib.h>
 13 #include <string.h>
 14 #include <assert.h>
 15 #include "helper.h"
 16 #include "msgUtil.h"
 17 
 18 #ifdef _ENABLE_STACK_TRACE_
 19 # include <execinfo.h>
 20 #endif
 21 
 22 #ifdef _WINDOWS
 23 #  include <Winsock2.h>       /* gethostbyname() */
 24 #else
 25 #  include <netdb.h>          /* gethostbyname_re() */
 26 #  include <errno.h>          /* gethostbyname_re() */
 27 #endif
 28 
 29 #if !defined(XMLBLASTER_NO_RCSID)
 30 /*
 31    Add the exact version of the C client library, this is for examination
 32    with for example the UNIX 'strings' command only.
 33    If it makes problem just set -DXMLBLASTER_NO_RCSID
 34 */
 35 #if defined(__GNUC__) || defined(__ICC)
 36    /* To support query state with 'ident libxmlBlasterClientC.so' or 'what libxmlBlasterClientC.so'
 37       or 'strings libxmlBlasterClientC.so  | grep msgUtil.c' */
 38    static const char *rcsid_GlobalCpp  __attribute__ ((unused)) =  "@(#) $Id: msgUtil.c 18164 2014-06-09 16:31:28Z ruff $ xmlBlaster @version@ #@revision.number@";
 39 #elif defined(__SUNPRO_CC)
 40    static const char *rcsid_GlobalCpp  =  "@(#) $Id: msgUtil.c 18164 2014-06-09 16:31:28Z ruff $ xmlBlaster @version@ #@revision.number@";
 41 #endif
 42 #endif
 43 
 44 /**
 45  * @return e.g. "0.848 #1207M"
 46  */
 47 Dll_Export const char *getXmlBlasterVersion(void)
 48 {
 49    /* Is replaced by xmlBlaster/build.xml ant task */
 50    static const char *p1 = "@version@";
 51    static const char *p2 = "@version@ #@revision.number@";
 52    if (strstr(p2, "@") == 0 && strstr(p2, "${") == 0) { /* Verify that subversion replacement worked fine */
 53        return p2;
 54    }
 55    if (strstr(p1, "@") == 0) { /* Verify that version replacement worked fine */
 56        return p1;
 57    }
 58    return "2.2.0";
 59 }
 60 
 61 /**
 62  * Frees the pointer with free().
 63  * <p>
 64  * Users of this library can use xmlBlasterFree() instead of free().
 65  * This can be helpful on Windows and if this client library is a DLL and compiled with /MT
 66  * but the client code is not (or vice versa).
 67  * In such a case the executable uses different runtime libraries
 68  * with different instances of malloc/free.
 69  * </p>
 70  * On UNIX we don't need this function but it doesn't harm either.
 71  */
 72 Dll_Export void xmlBlasterFree(char *p/*const char *p*/)
 73 {
 74    if (p != (char *)0) {
 75       free((void *)p);
 76    }
 77 }
 78 
 79 /**
 80  * Frees the pointer with free().
 81  * @param p The address of your pointer to be freed, *p is set to 0
 82  */
 83 Dll_Export void xmlBlasterFree0(char **p/*const char **p*/)
 84 {
 85         /*
 86         char *x = "J";
 87         const char *y = "J";
 88         const char * const z = "J";
 89         */
 90    if (p != (char **)0) {
 91       free(*p);
 92       *p = 0;
 93    }
 94 }
 95 
 96 Dll_Export SessionName *createSessionName(const char* const name) {
 97         SessionName * sessionName = 0;
 98         if (name == 0)
 99                 return 0;
100         sessionName = (SessionName *)calloc(1, sizeof(SessionName));
101         if (sessionName != 0)
102         {
103                 char *absoluteName = 0;
104                 sessionName->nodeId = 0;
105                 sessionName->subjectId = 0;
106                 sessionName->sessionId = 0;
107                 absoluteName = strcpyAlloc(name);
108                 trim(absoluteName);
109                 {
110                         char *p = strstr(absoluteName, "/");
111                         int len = strlen(absoluteName);
112                         if (p == 0 || len == 0) {
113                                 sessionName->subjectId = absoluteName;
114                                 return sessionName;
115                         }
116                         if (*absoluteName == '/') {
117                                 char *str1, *token;
118                                 char *saveptr1;
119                                 const char *sep = "/";
120                                 int j = 0;
121                                 for (str1 = absoluteName;; str1 = NULL) {
122                                         token = strtok_r(str1, sep, &saveptr1);
123                                         if (token == NULL)
124                                                 break;
125                                         if (!strcmp(token,"node") || !strcmp(token,"client") || !strcmp(token,"session"))
126                                                 continue;
127                                         if (j == 0)
128                                                 sessionName->nodeId = strcpyAlloc(token);
129                                         else if (j == 1)
130                                                 sessionName->subjectId = strcpyAlloc(token);
131                                         else if (j == 2)
132                                                 sscanf(token, "%d", &sessionName->sessionId);
133                                         j++;
134                                 }
135                         }
136                         else {
137                                 char *str1, *token;
138                                 char *saveptr1;
139                                 const char *sep = "/";
140                                 int j = 0;
141                                 for (str1 = absoluteName;; str1 = NULL) {
142                                         token = strtok_r(str1, sep, &saveptr1);
143                                         if (token == NULL)
144                                                 break;
145                                         if (!strcmp(token,"node") || !strcmp(token,"client") || !strcmp(token,"session"))
146                                                 continue;
147                                         if (j == 0)
148                                                 sessionName->subjectId = strcpyAlloc(token);
149                                         else if (j == 1)
150                                                 sscanf(token, "%d", &sessionName->sessionId);
151                                         j++;
152                                 }
153                         }
154                 }
155                 xmlBlasterFree(absoluteName);
156         }
157         return sessionName;
158 }
159 
160 Dll_Export void freeSessionName(SessionName *sessionName)
161 {
162         if (sessionName == 0) return;
163         xmlBlasterFree0((char **)&sessionName->nodeId);
164         xmlBlasterFree0((char **)&sessionName->subjectId);
165         free(sessionName);
166 }
167 
168 /**
169  * Frees everything inside QosArr and the struct QosArr itself
170  * @param qosArr The struct to free, passing NULL is OK
171  */
172 Dll_Export void freeQosArr(QosArr *qosArr)
173 {
174    size_t i;
175    if (qosArr == (QosArr *)0) return;
176    for (i=0; i<qosArr->len; i++) {
177       free((char *)qosArr->qosArr[i]);
178    }
179    free((char *)qosArr->qosArr);
180    qosArr->len = 0;
181    free(qosArr);
182 }
183 
184 /**
185  * Frees everything inside MsgUnitArr and the struct MsgUnitArr itself
186  * @param msgUnitArr The struct to free, passing NULL is OK
187  */
188 Dll_Export void freeMsgUnitArr(MsgUnitArr *msgUnitArr)
189 {
190    if (msgUnitArr == (MsgUnitArr *)0) return;
191    freeMsgUnitArrInternal(msgUnitArr);
192    free(msgUnitArr);
193 }
194 
195 /**
196  * Frees everything inside MsgUnitArr but NOT the struct MsgUnitArr itself
197  * @param msgUnitArr The struct internals to free, passing NULL is OK
198  */
199 Dll_Export void freeMsgUnitArrInternal(MsgUnitArr *msgUnitArr)
200 {
201    size_t i;
202    if (msgUnitArr == (MsgUnitArr *)0) return;
203    for (i=0; i<msgUnitArr->len; i++) {
204       freeMsgUnitData(&msgUnitArr->msgUnitArr[i]);
205    }
206    free(msgUnitArr->msgUnitArr);
207    msgUnitArr->len = 0;
208 }
209 
210 /**
211  * Does not free the msgUnit itself
212  */
213 Dll_Export void freeMsgUnitData(MsgUnit *msgUnit)
214 {
215    if (msgUnit == (MsgUnit *)0) return;
216    if (msgUnit->key != 0) {
217       free((char *)msgUnit->key);
218       msgUnit->key = 0;
219    }
220    if (msgUnit->content != 0) {
221       free((char *)msgUnit->content);
222       msgUnit->content = 0;
223    }
224    msgUnit->contentLen = 0;
225    if (msgUnit->qos != 0) {
226       free((char *)msgUnit->qos);
227       msgUnit->qos = 0;
228    }
229    if (msgUnit->responseQos != 0) {
230       free((char *)msgUnit->responseQos);
231       msgUnit->responseQos = 0;
232    }
233    /* free(msgUnit); -> not in this case, as the containing array has not allocated us separately */
234 }
235 
236 /**
237  * Frees everything.
238  */
239 Dll_Export void freeMsgUnit(MsgUnit *msgUnit)
240 {
241    if (msgUnit == (MsgUnit *)0) return;
242    freeMsgUnitData(msgUnit);
243    free(msgUnit);
244 }
245 
246 /**
247  * NOTE: You need to free the returned pointer with xmlBlasterFree() or directly with free()!
248  *
249  * @param msg The message
250  * @param maxContentDumpLen for -1 get the complete content, else limit the
251  *        content to the given number of bytes
252  * @return A ASCII XML formatted message or NULL if out of memory
253  */
254 Dll_Export char *messageUnitToXmlLimited(MsgUnit *msg, int maxContentDumpLen)
255 {
256    if (msg->key == 0 && msg->contentLen < 1) {
257       return strcpyAlloc(msg->qos);
258    }
259    else if (msg->contentLen < 1) {
260       char *xml = strcpyAlloc(msg->key);
261       if (xml == 0) return 0;
262       return strcatAlloc(&xml, msg->qos);
263    }
264    else {
265       char *contentStr = strFromBlobAlloc(msg->content, msg->contentLen);
266       size_t len = 200 + strlen(msg->key) + msg->contentLen + strlen(msg->qos);
267       char *xml = (char *)calloc(len, sizeof(char));
268       if (xml == 0) {
269          free(contentStr);
270          return 0;
271       }
272       if (maxContentDumpLen == 0)
273          *contentStr = 0;
274       else if (maxContentDumpLen > 0 && msg->contentLen > 5 && (size_t)maxContentDumpLen < (msg->contentLen-5))
275          strncpy0(contentStr+maxContentDumpLen, " ...", 5);
276       SNPRINTF(xml, len, "%s\n <content size='%lu'><![CDATA[%s]]></content>%s",
277                          msg->key, (unsigned long)msg->contentLen, contentStr, msg->qos);
278       free(contentStr);
279       return xml;
280    }
281 }
282 
283 /**
284  * NOTE: You need to free the returned pointer with xmlBlasterFree() or directly with free()!
285  *
286  * @return A ASCII XML formatted message or NULL if out of memory
287  */
288 Dll_Export char *messageUnitToXml(MsgUnit *msg)
289 {
290    return messageUnitToXmlLimited(msg, -1);
291 }
292 
293 /**
294  * Should be called on any xmlBlasterException before using it
295  */
296 Dll_Export _INLINE_FUNC void initializeXmlBlasterException(XmlBlasterException *xmlBlasterException)
297 {
298    xmlBlasterException->remote = false;
299    *xmlBlasterException->errorCode = (char)0;
300    *xmlBlasterException->message = (char)0;
301 }
302 
303 
304 /* a local version of the 6 argument call to gethostbyname_r
305    this is copied from http://www.cygwin.com/ml/cygwin/2004-04/msg00532.html
306    thanks to Enzo Michelangeli for this
307 */
308 #if defined(__FreeBSD__) || defined(__MacOSX__) || defined(__IPhoneOS__)
309    /* this should actually work for other platforms... so long as they support pthreads */
310 /* since this is a 6 arg format... just define that here */
311 #define HAVE_FUNC_GETHOSTBYNAME_R_6
312 /* duh? ERANGE value copied from web... */
313 #define ERANGE 34
314 int gethostbyname_r (const char *name,
315                      struct hostent *ret,
316                      char *buf,
317                      size_t buflen,
318                      struct hostent **result,
319                      int *h_errnop) {
320 
321   int hsave;
322   struct hostent *ph;
323   static pthread_mutex_t __mutex = PTHREAD_MUTEX_INITIALIZER;
324   pthread_mutex_lock(&__mutex); /* begin critical area */
325   hsave = h_errno;
326   ph = gethostbyname(name);
327   *h_errnop = h_errno; /* copy h_errno to *h_herrnop */
328 
329   if (ph == NULL) {
330     *result = NULL;
331   } else {
332     char **p, **q;
333     char *pbuf;
334     size_t nbytes=0;
335     int naddr=0, naliases=0;
336     /* determine if we have enough space in buf */
337 
338     /* count how many addresses */
339     for (p = ph->h_addr_list; p != 0 && *p != 0; p++) {
340       nbytes += ph->h_length; /* addresses */
341       nbytes += sizeof(*p); /* pointers */
342       naddr++;
343     }
344     nbytes += sizeof(*p); /* one more for the terminating NULL */
345 
346     /* count how many aliases, and total length of strings */
347 
348     for (p = ph->h_aliases; p != 0 && *p != 0; p++) {
349       nbytes += (strlen(*p)+1); /* aliases */
350       nbytes += sizeof(*p);  /* pointers */
351       naliases++;
352     }
353     nbytes += sizeof(*p); /* one more for the terminating NULL */
354 
355     /* here nbytes is the number of bytes required in buffer */
356     /* as a terminator must be there, the minimum value is ph->h_length */
357     if(nbytes > buflen) {
358       *result = NULL;
359       pthread_mutex_unlock(&__mutex); /* end critical area */
360       return ERANGE; /* not enough space in buf!! */
361     }
362 
363     /* There is enough space. Now we need to do a deep copy! */
364     /* Allocation in buffer:
365        from [0] to [(naddr-1) * sizeof(*p)]:
366          pointers to addresses
367        at [naddr * sizeof(*p)]:
368          NULL
369        from [(naddr+1) * sizeof(*p)] to [(naddr+naliases) * sizeof(*p)] :
370          pointers to aliases
371        at [(naddr+naliases+1) * sizeof(*p)]:
372          NULL
373        then naddr addresses (fixed length), and naliases aliases (asciiz).
374     */
375 
376     *ret = *ph;   /* copy whole structure (not its address!) */
377 
378     /* copy addresses */
379     q = (char **)buf; /* pointer to pointers area (type: char **) */
380     ret->h_addr_list = q; /* update pointer to address list */
381     pbuf = buf + ((naddr+naliases+2)*sizeof(*p)); /* skip that area */
382     for (p = ph->h_addr_list; p != 0 && *p != 0; p++) {
383       memcpy(pbuf, *p, (size_t)ph->h_length); /* copy address bytes */
384       *q++ = pbuf; /* the pointer is the one inside buf... */
385       pbuf += ph->h_length; /* advance pbuf */
386     }
387     *q++ = NULL; /* address list terminator */
388 
389     /* copy aliases */
390 
391     ret->h_aliases = q; /* update pointer to aliases list */
392     for (p = ph->h_aliases; p != 0 && *p != 0; p++) {
393       strcpy(pbuf, *p); /* copy alias strings */
394       *q++ = pbuf; /* the pointer is the one inside buf... */
395       pbuf += strlen(*p); /* advance pbuf */
396       *pbuf++ = 0; /* string terminator */
397     }
398     *q++ = NULL; /* terminator */
399 
400     strcpy(pbuf, ph->h_name); /* copy alias strings */
401     ret->h_name = pbuf;
402     pbuf += strlen(ph->h_name); /* advance pbuf */
403     *pbuf++ = 0; /* string terminator */
404 
405     *result = ret;  /* and let *result point to structure */
406 
407   }
408   h_errno = hsave;  /* restore h_errno */
409 
410   pthread_mutex_unlock(&__mutex); /* end critical area */
411 
412   return (*result == NULL);
413 
414 }
415 
416 #endif /* defined(__FreeBSD__) || defined(__MacOSX__) */
417 
418 #if defined(WINCE)
419 /* Ws2tcpip.h(550) : error C2632: 'int' followed by 'int' is illegal
420                      These errors are caused by redefinition in WinInet.h. */
421 /*#include <Ws2tcpip.h>*/ /* for getaddrinfo() only */
422 #endif
423 
424 /**
425  * Thread safe host lookup.
426  * NOTE: If the return is not NULL you need to free(*tmphstbuf)
427  * @author Caolan McNamara (2000) <caolan@skynet.ie> (with some leak fixes by Marcel)
428  */
429 Dll_Export struct hostent * gethostbyname_re (const char *host,struct hostent *hostbuf,
430                                               char **tmphstbuf,size_t *hstbuflen,
431                                               char errP[MAX_ERRNO_LEN])
432 {
433 #if defined(_WINDOWS_FUTURE)
434   /* See  http://www.hmug.org/man/3/getaddrinfo.html for an example */
435   /* #include Ws2tcpip.h
436    typedef struct addrinfo {
437       int ai_flags;
438       int ai_family;
439       int ai_socktype;
440       int ai_protocol;
441       size_t ai_addrlen;
442       char* ai_canonname;
443       struct sockaddr* ai_addr;
444       struct addrinfo* ai_next;
445    } addrinfo;
446 
447    struct sockaddr_in {
448         short   sin_family;
449         u_short sin_port;
450         struct  in_addr sin_addr;
451         char    sin_zero[8];
452    };
453    */
454 #   ifdef SOME_CLIENT_EXAMPLE
455       struct addrinfo hints, *res, *res0;
456       int error;
457       int s;
458       const char *cause = NULL;
459       const char* servname = "7609"; /* or "http" */
460       memset(&hints, 0, sizeof(hints));
461       hints.ai_family = PF_UNSPEC;
462       hints.ai_socktype = SOCK_STREAM;
463       error = getaddrinfo(host, servname, &hints, &res0);
464       if (error) {
465          errx(1, "%s", gai_strerror(error));
466          /*NOTREACHED*/
467       }
468       s = -1;
469       cause = "no addresses";
470       errno = EADDRNOTAVAIL;
471       for (res = res0; res; res = res->ai_next) {
472          s = socket(res->ai_family, res->ai_socktype,
473              res->ai_protocol);
474          if (s < 0) {
475             cause = "socket";
476             continue;
477          }
478          if (connect(s, res->ai_addr, res->ai_addrlen) < 0) {
479             cause = "connect";
480             close(s);
481             s = -1;
482             continue;
483          }
484          break;  /* okay we got one */
485       }
486       if (s < 0) {
487          err(1, cause);
488          /*NOTREACHED*/
489       }
490       freeaddrinfo(res0);
491 #   endif /* SOME_CLIENT_EXAMPLE */
492 #   ifdef SOME_SERVER_EXAMPLE
493      /* The following example tries to open a wildcard listening socket onto ser-
494      vice ``http'', for all the address families available. */
495 
496       struct addrinfo hints, *res, *res0;
497       int error;
498       int s[MAXSOCK];
499       int nsock;
500       const char* servname = "7609"; /* or "http" */
501       const char *cause = NULL;
502       memset(&hints, 0, sizeof(hints));
503       hints.ai_family = PF_UNSPEC;
504       hints.ai_socktype = SOCK_STREAM;
505       hints.ai_flags = AI_PASSIVE;
506       error = getaddrinfo(NULL, servname, &hints, &res0);
507       if (error) {
508          errx(1, "%s", gai_strerror(error));
509          /*NOTREACHED*/
510       }
511       nsock = 0;
512       for (res = res0; res && nsock < MAXSOCK; res = res->ai_next) {
513          s[nsock] = socket(res->ai_family, res->ai_socktype,
514              res->ai_protocol);
515          if (s[nsock] < 0) {
516             cause = "socket";
517             continue;
518          }
519          if (bind(s[nsock], res->ai_addr, res->ai_addrlen) < 0) {
520             cause = "bind";
521             close(s[nsock]);
522             continue;
523          }
524          if (listen(s[nsock], SOMAXCONN) < 0) {
525             cause = "listen";
526             close(s[nsock]);
527             continue;
528          }
529          nsock++;
530       }
531       if (nsock == 0) {
532          err(1, cause);
533          /*NOTREACHED*/
534       }
535       freeaddrinfo(res0);
536 #   endif /* SOME_SERVER_EXAMPLE */
537 #elif defined(__sun)
538       struct hostent *hp;
539       int herr;
540 
541       if (*hstbuflen == 0)
542       {
543          *hstbuflen = 1024;
544          *tmphstbuf = (char *)malloc (*hstbuflen);
545          if (*tmphstbuf == 0) return 0;
546       }
547 
548       while ((NULL == ( hp =
549          gethostbyname_r(host,hostbuf,*tmphstbuf,*hstbuflen,&herr)))
550          && (errno == ERANGE))
551       {
552          /* Enlarge the buffer. */
553          *hstbuflen *= 2;
554          *tmphstbuf = (char *)realloc (*tmphstbuf,*hstbuflen);
555          if (*tmphstbuf == 0) return 0;
556       }
557       return hp;
558 #elif defined(__alpha) /* OSF1 V5.1 1885 alpha */
559          if (*hstbuflen == 0)
560          {
561             *hstbuflen = sizeof(struct hostent_data);
562             *tmphstbuf = (char *)malloc (*hstbuflen);
563             if (*tmphstbuf == 0) return 0;
564          }
565          else if (*hstbuflen < sizeof(struct hostent_data))
566          {
567             *hstbuflen = sizeof(struct hostent_data);
568             *tmphstbuf = (char *)realloc(*tmphstbuf, *hstbuflen);
569             if (*tmphstbuf == 0) return 0;
570          }
571          memset((void *)(*tmphstbuf),0,*hstbuflen);
572 
573          if (0 != gethostbyname_r(host,hostbuf,(struct hostent_data *)*tmphstbuf)) {
574             free(*tmphstbuf);
575             *tmphstbuf = 0;
576             return 0;
577          }
578          return hostbuf;
579 #elif defined(WINCE)
580          /* Header: Winsock2.h. */
581          /* Link Library: Ws2.lib. */
582          struct hostent* remoteHost;
583          unsigned int addr;
584          const char *pp = 0;
585          hostbuf = 0;  /* Do something with unused arguments to avoid compiler warning */
586          tmphstbuf = 0;
587          hstbuflen = 0;
588          *errP = 0;
589          WSASetLastError(0);
590 
591 #if Ws2tcpip_USE
592          { /* The future preferred way, not yet ready implemented */
593             /*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.*/
594             const char FAR* servname = 0; /* Pointer to a NULL-terminated string containing either a service name or port number. */
595             const struct addrinfo hints; /* Pointer to an addrinfo structure that provides hints about the type of socket the caller supports.  */
596             struct addrinfo FAR* FAR* res; /* out */
597             int errorReturn = 0; /* return: This function returns zero when successful. The return of a nonzero Windows Sockets error code indicates failure. */
598             memset((char *)&hints, 0, sizeof(struct addrinfo));
599             errorReturn = getaddrinfo(host, servname, &hints, res);
600          }
601 #endif /*Ws2tcpip_USE*/
602 
603          /* If the user input is an alpha name for the host, use gethostbyname() */
604          if (isalpha(host[0])) {   /* host address is a name */
605            remoteHost = gethostbyname(host); /* Not thread safe, returns null on error (use WSAGetLastError() to retrieve reason) */
606            pp = "gethostbyname";
607          }
608          else  {
609            /* The gethostbyaddr function has been deprecated by the introduction of the getnameinfo function. */
610            /* If not, get host by addr (assume IPv4) e.g. "192.168.1.1" */
611            addr = inet_addr(host);
612            remoteHost = gethostbyaddr((char *) &addr, 4, AF_INET);
613            /* If an error occurs, it returns a NULL pointer, and a specific error code can be retrieved by calling WSAGetLastError. */
614            pp = "gethostbyaddr";
615          }
616          if (remoteHost == 0) {
617             int err = WSAGetLastError(); /* does not reset the error code, use WSASetLastError(0) to do it */
618             /* for error codes see http://msdn2.microsoft.com/en-us/library/ms740668.aspx */
619             /*if (WSAGetLastError() == 11001)
620                printf("Host %s not found\n", host);*/
621             /*printf("Host %s not found, WSAGetLastError=%d\n", host, err);*/
622             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);
623             WSASetLastError(0);
624             return 0;
625          }
626          else {
627             *errP = 0;
628             return remoteHost;
629          }
630 #elif defined(_WINDOWS)
631          /*Winsock2.h, Ws2_32.lib, Ws2_32.dll*/
632          struct hostent* remoteHost;
633          unsigned int addr;
634          const char *pp = 0;
635          hostbuf = 0;  /* Do something with unused arguments to avoid compiler warning */
636          tmphstbuf = 0;
637          hstbuflen = 0;
638          *errP = 0;
639          WSASetLastError(0);
640 
641          /* If the user input is an alpha name for the host, use gethostbyname() */
642          if (isalpha(host[0])) {   /* host address is a name */
643            remoteHost = gethostbyname(host); /* Not thread safe */
644            pp = "gethostbyname";
645          }
646          else  {
647            /* If not, get host by addr (assume IPv4) e.g. "192.168.1.1" */
648            addr = inet_addr(host);
649            remoteHost = gethostbyaddr((char *) &addr, 4, AF_INET);
650            pp = "gethostbyaddr";
651          }
652 
653          if (remoteHost == 0) {
654             int err = WSAGetLastError(); /* does not reset the error code, use WSASetLastError(0) to do it */
655             /* for error codes see http://msdn2.microsoft.com/en-us/library/ms740668.aspx */
656             /*if (WSAGetLastError() == 11001)
657                printf("Host %s not found\n", host);*/
658             /*printf("Host %s not found, WSAGetLastError=%d\n", host, err);*/
659             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);
660             WSASetLastError(0);
661             return 0;
662          }
663          else {
664             *errP = 0;
665             return remoteHost;
666          }
667 #else /* HAVE_FUNC_GETHOSTBYNAME_R_6 Linux */ /* defined(__hpux) with gcc 2.8 - 3.4.3 */
668    struct hostent *hp=0;
669    int herr=0,res=0;
670    if (errP != 0) *errP = 0; /* To avoid compiler warning */
671 
672    assert(tmphstbuf != 0);
673 
674    if (*hstbuflen == 0)
675    {
676       *hstbuflen = 1024;
677       *tmphstbuf = (char *)calloc (*hstbuflen, sizeof(char));
678       if (*tmphstbuf == 0) return 0;
679    }
680 
681    while (( res =
682       gethostbyname_r(host,hostbuf,*tmphstbuf,*hstbuflen,&hp,&herr))
683       && (errno == ERANGE))
684    {
685       /* Enlarge the buffer. */
686       *hstbuflen *= 2;
687       *tmphstbuf = (char *)realloc (*tmphstbuf,*hstbuflen);
688       if (*tmphstbuf == 0) return 0;
689    }
690    if (res != 0) {
691       free(*tmphstbuf);
692       *tmphstbuf = 0;
693       return 0;
694    }
695    return hp;
696 #endif
697 }
698 
699 # ifdef MSG_UTIL_MAIN
700 /* On Linux defaults to HAVE_FUNC_GETHOSTBYNAME_R_6:
701    gcc -g -Wall -o msgUtil msgUtil.c helper.c -I.. -DMSG_UTIL_MAIN=1
702 */
703 int main()
704 {
705    struct hostent hostbuf, *hostP = 0;
706    char *tmphstbuf=0;
707    size_t hstbuflen=0;
708    char serverHostName[256];
709    strcpy(serverHostName, "localhost");
710    hostP = gethostbyname_re(serverHostName, &hostbuf, &tmphstbuf, &hstbuflen);
711    printf("Hello '%s'\n", hostP->h_name);
712    return 0;
713 }
714 # endif


syntax highlighted by Code2HTML, v. 0.9.1