+
+// ============================================================================
+// implementation of thread-safe/reentrant functions if they're missing
+// ============================================================================
+
+// TODO: use POSIX getaddrinfo() (also available in Winsock 2) for simplicity
+// and to use the same code for IPv4 and IPv6 support
+
+#ifdef __WXMSW__
+ #define HAVE_INET_ADDR
+
+ #define HAVE_GETHOSTBYNAME
+ #define HAVE_GETSERVBYNAME
+
+ // under MSW getxxxbyname() functions are MT-safe (but not reentrant) so
+ // we don't need to serialize calls to them
+ #define wxHAS_MT_SAFE_GETBY_FUNCS
+
+ #if wxUSE_IPV6
+ // this header does dynamic dispatching of getaddrinfo/freeaddrinfo()
+ // by implementing them in its own code if the system versions are not
+ // available (as is the case for anything < XP)
+ //
+ // NB: if this is not available for the other compilers (so far tested
+ // with MSVC only) we should just use wxDynamicLibrary "manually"
+ #ifdef __VISUALC__
+ // disable a warning occurring in Microsoft own version of this file
+ #pragma warning(disable:4706)
+ #endif
+ #include <wspiapi.h>
+ #ifdef __VISUALC__
+ #pragma warning(default:4706)
+ #endif
+ #endif
+#endif // __WXMSW__
+
+// we assume that we have gethostbyaddr_r() if and only if we have
+// gethostbyname_r() and that it uses the similar conventions to it (see
+// comment in configure)
+#define HAVE_GETHOSTBYADDR HAVE_GETHOSTBYNAME
+#ifdef HAVE_FUNC_GETHOSTBYNAME_R_3
+ #define HAVE_FUNC_GETHOSTBYADDR_R_3
+#endif
+#ifdef HAVE_FUNC_GETHOSTBYNAME_R_5
+ #define HAVE_FUNC_GETHOSTBYADDR_R_5
+#endif
+#ifdef HAVE_FUNC_GETHOSTBYNAME_R_6
+ #define HAVE_FUNC_GETHOSTBYADDR_R_6
+#endif
+
+// the _r functions need the extra buffer parameter but unfortunately its type
+// differs between different systems and for the systems which use opaque
+// structs for it (at least AIX and OpenBSD) it must be zero-filled before
+// being passed to the system functions
+#ifdef HAVE_FUNC_GETHOSTBYNAME_R_3
+ struct wxGethostBuf : hostent_data
+ {
+ wxGethostBuf()
+ {
+ memset(this, 0, sizeof(hostent_data));
+ }
+ };
+#else
+ typedef char wxGethostBuf[1024];
+#endif
+
+#ifdef HAVE_FUNC_GETSERVBYNAME_R_4
+ struct wxGetservBuf : servent_data
+ {
+ wxGethostBuf()
+ {
+ memset(this, 0, sizeof(servent_data));
+ }
+ };
+#else
+ typedef char wxGetservBuf[1024];
+#endif
+
+#if defined(wxHAS_MT_SAFE_GETBY_FUNCS) || !wxUSE_THREADS
+ #define wxLOCK_GETBY_MUTEX(name)
+#else // may need mutexes to protect getxxxbyxxx() calls
+ #if defined(HAVE_GETHOSTBYNAME) || \
+ defined(HAVE_GETHOSTBYADDR) || \
+ defined(HAVE_GETSERVBYNAME)
+ #include "wx/thread.h"
+
+ namespace
+ {
+ // these mutexes are used to serialize
+ wxMutex nameLock, // gethostbyname()
+ addrLock, // gethostbyaddr()
+ servLock; // getservbyname()
+ }
+
+ #define wxLOCK_GETBY_MUTEX(name) wxMutexLocker locker(name ## Lock)
+ #endif // we don't have _r functions
+#endif // wxUSE_THREADS
+
+namespace
+{
+
+#if defined(HAVE_GETHOSTBYNAME)
+hostent *deepCopyHostent(hostent *h,
+ const hostent *he,
+ char *buffer,
+ int size,
+ int *err)
+{
+ /* copy old structure */
+ memcpy(h, he, sizeof(hostent));
+
+ /* copy name */
+ int len = strlen(h->h_name);
+ if (len > size)
+ {
+ *err = ENOMEM;
+ return NULL;
+ }
+ memcpy(buffer, h->h_name, len);
+ buffer[len] = '\0';
+ h->h_name = buffer;
+
+ /* track position in the buffer */
+ int pos = len + 1;
+
+ /* reuse len to store address length */
+ len = h->h_length;
+
+ /* ensure pointer alignment */
+ unsigned int misalign = sizeof(char *) - pos%sizeof(char *);
+ if(misalign < sizeof(char *))
+ pos += misalign;
+
+ /* leave space for pointer list */
+ char **p = h->h_addr_list, **q;
+ char **h_addr_list = (char **)(buffer + pos);
+ while(*(p++) != 0)
+ pos += sizeof(char *);
+
+ /* copy addresses and fill new pointer list */
+ for (p = h->h_addr_list, q = h_addr_list; *p != 0; p++, q++)
+ {
+ if (size < pos + len)
+ {
+ *err = ENOMEM;
+ return NULL;
+ }
+ memcpy(buffer + pos, *p, len); /* copy content */
+ *q = buffer + pos; /* set copied pointer to copied content */
+ pos += len;
+ }
+ *++q = 0; /* null terminate the pointer list */
+ h->h_addr_list = h_addr_list; /* copy pointer to pointers */
+
+ /* ensure word alignment of pointers */
+ misalign = sizeof(char *) - pos%sizeof(char *);
+ if(misalign < sizeof(char *))
+ pos += misalign;
+
+ /* leave space for pointer list */
+ p = h->h_aliases;
+ char **h_aliases = (char **)(buffer + pos);
+ while(*(p++) != 0)
+ pos += sizeof(char *);
+
+ /* copy aliases and fill new pointer list */
+ for (p = h->h_aliases, q = h_aliases; *p != 0; p++, q++)
+ {
+ len = strlen(*p);
+ if (size <= pos + len)
+ {
+ *err = ENOMEM;
+ return NULL;
+ }
+ memcpy(buffer + pos, *p, len); /* copy content */
+ buffer[pos + len] = '\0';
+ *q = buffer + pos; /* set copied pointer to copied content */
+ pos += len + 1;
+ }
+ *++q = 0; /* null terminate the pointer list */
+ h->h_aliases = h_aliases; /* copy pointer to pointers */
+
+ return h;
+}
+#endif // HAVE_GETHOSTBYNAME
+
+hostent *wxGethostbyname_r(const char *hostname,
+ hostent *h,
+ wxGethostBuf buffer,
+ int size,
+ int *err)
+{
+ hostent *he;
+#if defined(HAVE_FUNC_GETHOSTBYNAME_R_6)
+ gethostbyname_r(hostname, h, buffer, size, &he, err);
+#elif defined(HAVE_FUNC_GETHOSTBYNAME_R_5)
+ he = gethostbyname_r(hostname, h, buffer, size, err);
+#elif defined(HAVE_FUNC_GETHOSTBYNAME_R_3)
+ he = gethostbyname_r(hostname, h, &buffer);
+ *err = h_errno;
+#elif defined(HAVE_GETHOSTBYNAME)
+ wxLOCK_GETBY_MUTEX(name);
+
+ he = gethostbyname(hostname);
+ *err = h_errno;
+
+ if ( he )
+ he = deepCopyHostent(h, he, buffer, size, err);
+#else
+ #error "No gethostbyname[_r]()"
+#endif
+
+ return he;
+}
+
+hostent *wxGethostbyaddr_r(const char *addr_buf,
+ int buf_size,
+ int proto,
+ hostent *h,
+ wxGethostBuf buffer,
+ int size,
+ int *err)
+{
+ hostent *he;
+#if defined(HAVE_FUNC_GETHOSTBYADDR_R_6)
+ gethostbyaddr_r(addr_buf, buf_size, proto, h, buffer, size, &he, err);
+#elif defined(HAVE_FUNC_GETHOSTBYADDR_R_5)
+ he = gethostbyaddr_r(addr_buf, buf_size, proto, h, buffer, size, err);
+#elif defined(HAVE_FUNC_GETHOSTBYADDR_R_3)
+ he = gethostbyaddr_r(addr_buf, buf_size, proto, h, buffer);
+ *err = h_errno;
+#elif defined(HAVE_GETHOSTBYADDR)
+ wxLOCK_GETBY_MUTEX(addr);
+
+ he = gethostbyaddr(addr_buf, buf_size, proto);
+ *err = h_errno;
+
+ if ( he )
+ he = deepCopyHostent(h, he, buffer, size, err);
+#else
+ #error "No gethostbyaddr[_r]()"
+#endif
+
+ return he;
+}
+
+#if defined(HAVE_GETSERVBYNAME)
+servent *deepCopyServent(servent *s,
+ servent *se,
+ char *buffer,
+ int size)
+{
+ /* copy plain old structure */
+ memcpy(s, se, sizeof(servent));
+
+ /* copy name */
+ int len = strlen(s->s_name);
+ if (len >= size)
+ {
+ return NULL;
+ }
+ memcpy(buffer, s->s_name, len);
+ buffer[len] = '\0';
+ s->s_name = buffer;
+
+ /* track position in the buffer */
+ int pos = len + 1;
+
+ /* copy protocol */
+ len = strlen(s->s_proto);
+ if (pos + len >= size)
+ {
+ return NULL;
+ }
+ memcpy(buffer + pos, s->s_proto, len);
+ buffer[pos + len] = '\0';
+ s->s_proto = buffer + pos;
+
+ /* track position in the buffer */
+ pos += len + 1;
+
+ /* ensure pointer alignment */
+ unsigned int misalign = sizeof(char *) - pos%sizeof(char *);
+ if(misalign < sizeof(char *))
+ pos += misalign;
+
+ /* leave space for pointer list */
+ char **p = s->s_aliases, **q;
+ char **s_aliases = (char **)(buffer + pos);
+ while(*(p++) != 0)
+ pos += sizeof(char *);
+
+ /* copy addresses and fill new pointer list */
+ for (p = s->s_aliases, q = s_aliases; *p != 0; p++, q++){
+ len = strlen(*p);
+ if (size <= pos + len)
+ {
+ return NULL;
+ }
+ memcpy(buffer + pos, *p, len); /* copy content */
+ buffer[pos + len] = '\0';
+ *q = buffer + pos; /* set copied pointer to copied content */
+ pos += len + 1;
+ }
+ *++q = 0; /* null terminate the pointer list */
+ s->s_aliases = s_aliases; /* copy pointer to pointers */
+ return s;
+}
+#endif // HAVE_GETSERVBYNAME
+
+servent *wxGetservbyname_r(const char *port,
+ const char *protocol,
+ servent *serv,
+ wxGetservBuf& buffer,
+ int size)
+{
+ servent *se;
+#if defined(HAVE_FUNC_GETSERVBYNAME_R_6)
+ getservbyname_r(port, protocol, serv, buffer, size, &se);
+#elif defined(HAVE_FUNC_GETSERVBYNAME_R_5)
+ se = getservbyname_r(port, protocol, serv, buffer, size);
+#elif defined(HAVE_FUNC_GETSERVBYNAME_R_4)
+ if ( getservbyname_r(port, protocol, serv, &buffer) != 0 )
+ return NULL;
+#elif defined(HAVE_GETSERVBYNAME)
+ wxLOCK_GETBY_MUTEX(serv);
+
+ se = getservbyname(port, protocol);
+ if ( se )
+ se = deepCopyServent(serv, se, buffer, size);
+#else
+ #error "No getservbyname[_r]()"