+// 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]()"
+#endif
+ return se;
+}
+
+} // anonymous namespace
+
+// ============================================================================
+// wxSockAddressImpl implementation
+// ============================================================================
+
+// FIXME-VC6: helper macros to call Alloc/Get() hiding the ugly dummy argument
+#define ALLOC(T) Alloc(static_cast<T *>(NULL))
+#define GET(T) Get(static_cast<T *>(NULL))
+
+// ----------------------------------------------------------------------------
+// INET or INET6 address family
+// ----------------------------------------------------------------------------
+
+wxString wxSockAddressImpl::GetHostName() const
+{
+ const void *addrbuf;
+ int addrbuflen;
+
+#if wxUSE_IPV6
+ if ( m_family == FAMILY_INET6 )
+ {
+ sockaddr_in6 * const addr6 = GET(sockaddr_in6);
+ addrbuf = &addr6->sin6_addr;
+ addrbuflen = sizeof(addr6->sin6_addr);
+ }
+ else
+#endif // wxUSE_IPV6
+ {
+ sockaddr_in * const addr = GET(sockaddr_in);
+ if ( !addr )
+ return wxString();
+
+ addrbuf = &addr->sin_addr;
+ addrbuflen = sizeof(addr->sin_addr);
+ }
+
+ hostent he;
+ wxGethostBuf buffer;
+ int err;
+ if ( !wxGethostbyaddr_r
+ (
+ static_cast<const char *>(addrbuf),
+ addrbuflen,
+ m_family,
+ &he,
+ buffer,
+ sizeof(buffer),
+ &err
+ ) )
+ {
+ return wxString();
+ }
+
+ return wxString::FromUTF8(he.h_name);
+}
+
+bool wxSockAddressImpl::SetPortName(const wxString& name, const char *protocol)
+{
+ // test whether it's a number first
+ unsigned long port;
+ if ( name.ToULong(&port) )
+ {
+ if ( port > 65535 )
+ return false;
+ }
+ else // it's a service name
+ {
+ wxGetservBuf buffer;
+ servent se;
+ if ( !wxGetservbyname_r(name.utf8_str(), protocol, &se,
+ buffer, sizeof(buffer)) )
+ return false;
+
+ // s_port is in network byte order and SetPort() uses the host byte
+ // order and we prefer to reuse it from here instead of assigning to
+ // sin_port directly
+ port = ntohs(se.s_port);
+ }
+
+ return SetPort(port);
+}
+
+// ----------------------------------------------------------------------------
+// INET address family
+// ----------------------------------------------------------------------------
+
+void wxSockAddressImpl::CreateINET()
+{
+ wxASSERT_MSG( Is(FAMILY_UNSPEC), "recreating address as different type?" );
+
+ m_family = FAMILY_INET;
+ sockaddr_in * const addr = ALLOC(sockaddr_in);
+ addr->sin_family = FAMILY_INET;
+}
+
+bool wxSockAddressImpl::SetHostName4(const wxString& name)
+{
+ sockaddr_in * const addr = GET(sockaddr_in);
+ if ( !addr )
+ return false;
+
+ const wxScopedCharBuffer namebuf(name.utf8_str());
+
+ // first check if this is an address in quad dotted notation
+#if defined(HAVE_INET_ATON)
+ if ( inet_aton(namebuf, &addr->sin_addr) )
+ return true;
+#elif defined(HAVE_INET_ADDR)
+ addr->sin_addr.s_addr = inet_addr(namebuf);
+ if ( addr->sin_addr.s_addr != INADDR_NONE )
+ return true;
+#else
+ #error "Neither inet_aton() nor inet_addr() is available?"
+#endif
+
+ // it's a host name, resolve it
+ hostent he;
+ wxGethostBuf buffer;
+ int err;
+ if ( !wxGethostbyname_r(namebuf, &he, buffer, sizeof(buffer), &err) )
+ return false;
+
+ addr->sin_addr.s_addr = ((in_addr *)he.h_addr)->s_addr;
+ return true;
+}
+
+bool wxSockAddressImpl::GetHostAddress(wxUint32 *address) const