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