1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/common/sckaddr.cpp
3 // Purpose: Network address manager
4 // Author: Guilhem Lavaux
6 // Modified by: Vadim Zeitlin to use wxSockAddressImpl on 2008-12-28
8 // Copyright: (c) 1997, 1998 Guilhem Lavaux
9 // (c) 2008 Vadim Zeitlin
10 // Licence: wxWindows licence
11 /////////////////////////////////////////////////////////////////////////////
13 // ============================================================================
15 // ============================================================================
17 // ----------------------------------------------------------------------------
19 // ----------------------------------------------------------------------------
21 // For compilers that support precompilation, includes "wx.h".
22 #include "wx/wxprec.h"
31 #include "wx/object.h"
39 #if !defined(__MWERKS__)
44 #include "wx/socket.h"
45 #include "wx/sckaddr.h"
46 #include "wx/private/socket.h"
47 #include "wx/private/sckaddr.h"
51 #include <arpa/inet.h>
55 #define INADDR_NONE INADDR_ANY
58 // ----------------------------------------------------------------------------
60 // ----------------------------------------------------------------------------
62 IMPLEMENT_ABSTRACT_CLASS(wxSockAddress
, wxObject
)
63 IMPLEMENT_ABSTRACT_CLASS(wxIPaddress
, wxSockAddress
)
64 IMPLEMENT_DYNAMIC_CLASS(wxIPV4address
, wxIPaddress
)
66 IMPLEMENT_DYNAMIC_CLASS(wxIPV6address
, wxIPaddress
)
68 #if defined(__UNIX__) && !defined(__WINDOWS__) && !defined(__WINE__)
69 IMPLEMENT_DYNAMIC_CLASS(wxUNIXaddress
, wxSockAddress
)
72 // ============================================================================
73 // implementation of thread-safe/reentrant functions if they're missing
74 // ============================================================================
76 // TODO: use POSIX getaddrinfo() (also available in Winsock 2) for simplicity
77 // and to use the same code for IPv4 and IPv6 support
80 #define HAVE_INET_ADDR
82 #define HAVE_GETHOSTBYNAME
83 #define HAVE_GETSERVBYNAME
85 // under MSW getxxxbyname() functions are MT-safe (but not reentrant) so
86 // we don't need to serialize calls to them
87 #define wxHAS_MT_SAFE_GETBY_FUNCS
90 // this header does dynamic dispatching of getaddrinfo/freeaddrinfo()
91 // by implementing them in its own code if the system versions are not
92 // available (as is the case for anything < XP)
94 // NB: if this is not available for the other compilers (so far tested
95 // with MSVC only) we should just use wxDynamicLibrary "manually"
97 // disable a warning occurring in Microsoft own version of this file
98 #pragma warning(disable:4706)
102 #pragma warning(default:4706)
107 // we assume that we have gethostbyaddr_r() if and only if we have
108 // gethostbyname_r() and that it uses the similar conventions to it (see
109 // comment in configure)
110 #define HAVE_GETHOSTBYADDR HAVE_GETHOSTBYNAME
111 #ifdef HAVE_FUNC_GETHOSTBYNAME_R_3
112 #define HAVE_FUNC_GETHOSTBYADDR_R_3
114 #ifdef HAVE_FUNC_GETHOSTBYNAME_R_5
115 #define HAVE_FUNC_GETHOSTBYADDR_R_5
117 #ifdef HAVE_FUNC_GETHOSTBYNAME_R_6
118 #define HAVE_FUNC_GETHOSTBYADDR_R_6
121 // the _r functions need the extra buffer parameter but unfortunately its type
122 // differs between different systems
123 #ifdef HAVE_FUNC_GETHOSTBYNAME_R_3
124 typedef hostent_data wxGethostBuf
;
126 typedef char wxGethostBuf
[1024];
129 #ifdef HAVE_FUNC_GETSERVBYNAME_R_3
130 typedef servent_data wxGetservBuf
;
132 typedef char wxGetservBuf
[1024];
135 #ifdef wxHAS_MT_SAFE_GETBY_FUNCS
136 #define wxLOCK_GETBY_MUTEX(name)
137 #else // may need mutexes to protect getxxxbyxxx() calls
138 #if defined(HAVE_GETHOSTBYNAME) || \
139 defined(HAVE_GETHOSTBYADDR) || \
140 defined(HAVE_GETSERVBYNAME)
141 #include "wx/thread.h"
145 // these mutexes are used to serialize
146 wxMutex nameLock
, // gethostbyname()
147 addrLock
, // gethostbyaddr()
148 servLock
; // getservbyname()
151 #define wxLOCK_GETBY_MUTEX(name) wxMutexLocker locker(name ## Lock)
152 #endif // we don't have _r functions
153 #endif // wxUSE_THREADS
158 #if defined(HAVE_GETHOSTBYNAME)
159 hostent
*deepCopyHostent(hostent
*h
,
165 /* copy old structure */
166 memcpy(h
, he
, sizeof(hostent
));
169 int len
= strlen(h
->h_name
);
175 memcpy(buffer
, h
->h_name
, len
);
179 /* track position in the buffer */
182 /* reuse len to store address length */
185 /* ensure pointer alignment */
186 unsigned int misalign
= sizeof(char *) - pos%sizeof
(char *);
187 if(misalign
< sizeof(char *))
190 /* leave space for pointer list */
191 char **p
= h
->h_addr_list
, **q
;
192 char **h_addr_list
= (char **)(buffer
+ pos
);
194 pos
+= sizeof(char *);
196 /* copy addresses and fill new pointer list */
197 for (p
= h
->h_addr_list
, q
= h_addr_list
; *p
!= 0; p
++, q
++)
199 if (size
< pos
+ len
)
204 memcpy(buffer
+ pos
, *p
, len
); /* copy content */
205 *q
= buffer
+ pos
; /* set copied pointer to copied content */
208 *++q
= 0; /* null terminate the pointer list */
209 h
->h_addr_list
= h_addr_list
; /* copy pointer to pointers */
211 /* ensure word alignment of pointers */
212 misalign
= sizeof(char *) - pos%sizeof
(char *);
213 if(misalign
< sizeof(char *))
216 /* leave space for pointer list */
218 char **h_aliases
= (char **)(buffer
+ pos
);
220 pos
+= sizeof(char *);
222 /* copy aliases and fill new pointer list */
223 for (p
= h
->h_aliases
, q
= h_aliases
; *p
!= 0; p
++, q
++)
226 if (size
<= pos
+ len
)
231 memcpy(buffer
+ pos
, *p
, len
); /* copy content */
232 buffer
[pos
+ len
] = '\0';
233 *q
= buffer
+ pos
; /* set copied pointer to copied content */
236 *++q
= 0; /* null terminate the pointer list */
237 h
->h_aliases
= h_aliases
; /* copy pointer to pointers */
241 #endif // HAVE_GETHOSTBYNAME
243 hostent
*wxGethostbyname_r(const char *hostname
,
250 #if defined(HAVE_FUNC_GETHOSTBYNAME_R_6)
251 gethostbyname_r(hostname
, h
, buffer
, size
, &he
, err
);
252 #elif defined(HAVE_FUNC_GETHOSTBYNAME_R_5)
253 he
= gethostbyname_r(hostname
, h
, buffer
, size
, err
);
254 #elif defined(HAVE_FUNC_GETHOSTBYNAME_R_3)
255 he
= gethostbyname_r(hostname
, h
, &buffer
);
257 #elif defined(HAVE_GETHOSTBYNAME)
258 wxLOCK_GETBY_MUTEX(name
);
260 he
= gethostbyname(hostname
);
264 he
= deepCopyHostent(h
, he
, buffer
, size
, err
);
266 #error "No gethostbyname[_r]()"
272 hostent
*wxGethostbyaddr_r(const char *addr_buf
,
281 #if defined(HAVE_FUNC_GETHOSTBYADDR_R_6)
282 gethostbyaddr_r(addr_buf
, buf_size
, proto
, h
, buffer
, size
, &he
, err
);
283 #elif defined(HAVE_FUNC_GETHOSTBYADDR_R_5)
284 he
= gethostbyaddr_r(addr_buf
, buf_size
, proto
, h
, buffer
, size
, err
);
285 #elif defined(HAVE_FUNC_GETHOSTBYADDR_R_3)
286 he
= gethostbyaddr_r(addr_buf
, buf_size
, proto
, h
, buffer
);
288 #elif defined(HAVE_GETHOSTBYADDR)
289 wxLOCK_GETBY_MUTEX(addr
);
291 he
= gethostbyaddr(addr_buf
, buf_size
, proto
);
295 he
= deepCopyHostent(h
, he
, buffer
, size
, err
);
297 #error "No gethostbyaddr[_r]()"
303 #if defined(HAVE_GETSERVBYNAME)
304 servent
*deepCopyServent(servent
*s
,
309 /* copy plain old structure */
310 memcpy(s
, se
, sizeof(servent
));
313 int len
= strlen(s
->s_name
);
318 memcpy(buffer
, s
->s_name
, len
);
322 /* track position in the buffer */
326 len
= strlen(s
->s_proto
);
327 if (pos
+ len
>= size
)
331 memcpy(buffer
+ pos
, s
->s_proto
, len
);
332 buffer
[pos
+ len
] = '\0';
333 s
->s_proto
= buffer
+ pos
;
335 /* track position in the buffer */
338 /* ensure pointer alignment */
339 unsigned int misalign
= sizeof(char *) - pos%sizeof
(char *);
340 if(misalign
< sizeof(char *))
343 /* leave space for pointer list */
344 char **p
= s
->s_aliases
, **q
;
345 char **s_aliases
= (char **)(buffer
+ pos
);
347 pos
+= sizeof(char *);
349 /* copy addresses and fill new pointer list */
350 for (p
= s
->s_aliases
, q
= s_aliases
; *p
!= 0; p
++, q
++){
352 if (size
<= pos
+ len
)
356 memcpy(buffer
+ pos
, *p
, len
); /* copy content */
357 buffer
[pos
+ len
] = '\0';
358 *q
= buffer
+ pos
; /* set copied pointer to copied content */
361 *++q
= 0; /* null terminate the pointer list */
362 s
->s_aliases
= s_aliases
; /* copy pointer to pointers */
365 #endif // HAVE_GETSERVBYNAME
367 servent
*wxGetservbyname_r(const char *port
,
368 const char *protocol
,
374 #if defined(HAVE_FUNC_GETSERVBYNAME_R_6)
375 getservbyname_r(port
, protocol
, serv
, buffer
, size
, &se
);
376 #elif defined(HAVE_FUNC_GETSERVBYNAME_R_5)
377 se
= getservbyname_r(port
, protocol
, serv
, buffer
, size
);
378 #elif defined(HAVE_FUNC_GETSERVBYNAME_R_4)
379 se
= getservbyname_r(port
, protocol
, serv
, &buffer
);
380 #elif defined(HAVE_GETSERVBYNAME)
381 wxLOCK_GETBY_MUTEX(serv
);
383 se
= getservbyname(port
, protocol
);
385 se
= deepCopyServent(serv
, se
, buffer
, size
);
387 #error "No getservbyname[_r]()"
392 } // anonymous namespace
394 // ============================================================================
395 // wxSockAddressImpl implementation
396 // ============================================================================
398 // FIXME-VC6: helper macros to call Alloc/Get() hiding the ugly dummy argument
399 #define ALLOC(T) Alloc(static_cast<T *>(NULL))
400 #define GET(T) Get(static_cast<T *>(NULL))
402 // ----------------------------------------------------------------------------
403 // INET or INET6 address family
404 // ----------------------------------------------------------------------------
406 wxString
wxSockAddressImpl::GetHostName() const
412 if ( m_family
== FAMILY_INET6
)
414 sockaddr_in6
* const addr6
= GET(sockaddr_in6
);
415 addrbuf
= &addr6
->sin6_addr
;
416 addrbuflen
= sizeof(addr6
->sin6_addr
);
421 sockaddr_in
* const addr
= GET(sockaddr_in
);
425 addrbuf
= &addr
->sin_addr
;
426 addrbuflen
= sizeof(addr
->sin_addr
);
432 if ( !wxGethostbyaddr_r
434 static_cast<const char *>(addrbuf
),
446 return wxString::FromUTF8(he
.h_name
);
449 bool wxSockAddressImpl::SetPortName(const wxString
& name
, const char *protocol
)
451 // test whether it's a number first
453 if ( name
.ToULong(&port
) )
458 else // it's a service name
462 if ( !wxGetservbyname_r(name
.utf8_str(), protocol
, &se
,
463 buffer
, sizeof(buffer
)) )
466 // s_port is in network byte order and SetPort() uses the host byte
467 // order and we prefer to reuse it from here instead of assigning to
469 port
= ntohs(se
.s_port
);
472 return SetPort(port
);
475 // ----------------------------------------------------------------------------
476 // INET address family
477 // ----------------------------------------------------------------------------
479 void wxSockAddressImpl::CreateINET()
481 wxASSERT_MSG( Is(FAMILY_UNSPEC
), "recreating address as different type?" );
483 m_family
= FAMILY_INET
;
484 sockaddr_in
* const addr
= ALLOC(sockaddr_in
);
485 addr
->sin_family
= FAMILY_INET
;
488 bool wxSockAddressImpl::SetHostName4(const wxString
& name
)
490 sockaddr_in
* const addr
= GET(sockaddr_in
);
494 const wxUTF8Buf
namebuf(name
.utf8_str());
496 // first check if this is an address in quad dotted notation
497 #if defined(HAVE_INET_ATON)
498 if ( inet_aton(namebuf
, &addr
->sin_addr
) )
500 #elif defined(HAVE_INET_ADDR)
501 addr
->sin_addr
.s_addr
= inet_addr(namebuf
);
502 if ( addr
->sin_addr
.s_addr
!= INADDR_NONE
)
505 #error "Neither inet_aton() nor inet_addr() is available?"
508 // it's a host name, resolve it
512 if ( !wxGethostbyname_r(namebuf
, &he
, buffer
, sizeof(buffer
), &err
) )
515 addr
->sin_addr
.s_addr
= ((in_addr
*)he
.h_addr
)->s_addr
;
519 bool wxSockAddressImpl::GetHostAddress(wxUint32
*address
) const
521 sockaddr_in
* const addr
= GET(sockaddr_in
);
525 *address
= ntohl(addr
->sin_addr
.s_addr
);
530 bool wxSockAddressImpl::SetHostAddress(wxUint32 address
)
532 sockaddr_in
* const addr
= GET(sockaddr_in
);
536 addr
->sin_addr
.s_addr
= htonl(address
);
541 wxUint16
wxSockAddressImpl::GetPort4() const
543 sockaddr_in
* const addr
= GET(sockaddr_in
);
547 return ntohs(addr
->sin_port
);
550 bool wxSockAddressImpl::SetPort4(wxUint16 port
)
552 sockaddr_in
* const addr
= GET(sockaddr_in
);
556 addr
->sin_port
= htons(port
);
563 // ----------------------------------------------------------------------------
564 // INET6 address family
565 // ----------------------------------------------------------------------------
567 void wxSockAddressImpl::CreateINET6()
569 wxASSERT_MSG( Is(FAMILY_UNSPEC
), "recreating address as different type?" );
571 m_family
= FAMILY_INET6
;
572 sockaddr_in6
* const addr
= ALLOC(sockaddr_in6
);
573 addr
->sin6_family
= FAMILY_INET6
;
576 bool wxSockAddressImpl::SetHostName6(const wxString
& hostname
)
578 sockaddr_in6
* const addr
= GET(sockaddr_in6
);
583 memset(&hints
, 0, sizeof(hints
));
584 hints
.ai_family
= AF_INET6
;
586 addrinfo
*info
= NULL
;
587 int rc
= getaddrinfo(hostname
.utf8_str(), NULL
, &hints
, &info
);
590 // use gai_strerror()?
594 wxCHECK_MSG( info
, false, "should have info on success" );
596 wxASSERT_MSG( int(info
->ai_addrlen
) == m_len
, "unexpected address length" );
598 memcpy(addr
, info
->ai_addr
, info
->ai_addrlen
);
604 bool wxSockAddressImpl::GetHostAddress(in6_addr
*address
) const
606 sockaddr_in6
* const addr
= GET(sockaddr_in6
);
610 *address
= addr
->sin6_addr
;
615 bool wxSockAddressImpl::SetHostAddress(const in6_addr
& address
)
617 sockaddr_in6
* const addr
= GET(sockaddr_in6
);
621 addr
->sin6_addr
= address
;
626 wxUint16
wxSockAddressImpl::GetPort6() const
628 sockaddr_in6
* const addr
= GET(sockaddr_in6
);
632 return ntohs(addr
->sin6_port
);
635 bool wxSockAddressImpl::SetPort6(wxUint16 port
)
637 sockaddr_in6
* const addr
= GET(sockaddr_in6
);
641 addr
->sin6_port
= htons(port
);
646 bool wxSockAddressImpl::SetToAnyAddress6()
648 static const in6_addr any
= IN6ADDR_ANY_INIT
;
650 return SetHostAddress(any
);
655 #ifdef wxHAS_UNIX_DOMAIN_SOCKETS
657 // ----------------------------------------------------------------------------
658 // Unix address family
659 // ----------------------------------------------------------------------------
661 #ifndef UNIX_PATH_MAX
662 #define UNIX_PATH_MAX (WXSIZEOF(((sockaddr_un *)NULL)->sun_path))
665 void wxSockAddressImpl::CreateUnix()
667 wxASSERT_MSG( Is(FAMILY_UNSPEC
), "recreating address as different type?" );
669 m_family
= FAMILY_UNIX
;
670 sockaddr_un
* const addr
= ALLOC(sockaddr_un
);
671 addr
->sun_family
= FAMILY_UNIX
;
672 addr
->sun_path
[0] = '\0';
675 bool wxSockAddressImpl::SetPath(const wxString
& path
)
677 sockaddr_un
* const addr
= GET(sockaddr_un
);
681 const wxUTF8Buf
buf(path
.utf8_str());
682 if ( strlen(buf
) >= UNIX_PATH_MAX
)
685 wxStrlcpy(addr
->sun_path
, buf
, UNIX_PATH_MAX
);
690 wxString
wxSockAddressImpl::GetPath() const
692 sockaddr_un
* const addr
= GET(sockaddr_un
);
696 return wxString::FromUTF8(addr
->sun_path
);
699 #endif // wxHAS_UNIX_DOMAIN_SOCKETS
704 // ----------------------------------------------------------------------------
706 // ----------------------------------------------------------------------------
708 void wxSockAddress::Init()
710 if ( !wxSocketBase::IsInitialized() )
712 // we must do it before using any socket functions
713 (void)wxSocketBase::Initialize();
717 wxSockAddress::wxSockAddress()
721 m_impl
= new wxSockAddressImpl();
724 wxSockAddress::wxSockAddress(const wxSockAddress
& other
)
729 m_impl
= new wxSockAddressImpl(*other
.m_impl
);
732 wxSockAddress::~wxSockAddress()
737 void wxSockAddress::SetAddress(const wxSockAddressImpl
& address
)
739 if ( &address
!= m_impl
)
742 m_impl
= new wxSockAddressImpl(address
);
746 wxSockAddress
& wxSockAddress::operator=(const wxSockAddress
& addr
)
748 SetAddress(addr
.GetAddress());
753 void wxSockAddress::Clear()
758 // ----------------------------------------------------------------------------
760 // ----------------------------------------------------------------------------
762 wxSockAddressImpl
& wxIPaddress::GetImpl()
764 if ( m_impl
->GetFamily() == wxSockAddressImpl::FAMILY_UNSPEC
)
765 m_impl
->CreateINET();
770 bool wxIPaddress::Hostname(const wxString
& name
)
772 wxCHECK_MSG( !name
.empty(), false, "empty host name is invalid" );
774 m_origHostname
= name
;
776 return GetImpl().SetHostName(name
);
779 bool wxIPaddress::Service(const wxString
& name
)
781 return GetImpl().SetPortName(name
, "tcp");
784 bool wxIPaddress::Service(unsigned short port
)
786 return GetImpl().SetPort(port
);
789 bool wxIPaddress::LocalHost()
791 return Hostname("localhost");
794 wxString
wxIPaddress::Hostname() const
796 return GetImpl().GetHostName();
799 unsigned short wxIPaddress::Service() const
801 return GetImpl().GetPort();
804 bool wxIPaddress::operator==(const wxIPaddress
& addr
) const
806 return Hostname().Cmp(addr
.Hostname()) == 0 &&
807 Service() == addr
.Service();
810 bool wxIPaddress::AnyAddress()
812 return GetImpl().SetToAnyAddress();
815 // ----------------------------------------------------------------------------
817 // ----------------------------------------------------------------------------
819 void wxIPV4address::DoInitImpl()
821 m_impl
->CreateINET();
824 bool wxIPV4address::Hostname(unsigned long addr
)
826 if ( !GetImpl().SetHostAddress(addr
) )
828 m_origHostname
.clear();
832 m_origHostname
= Hostname();
836 bool wxIPV4address::IsLocalHost() const
838 return Hostname() == "localhost" || IPAddress() == "127.0.0.1";
841 wxString
wxIPV4address::IPAddress() const
844 if ( !GetImpl().GetHostAddress(&addr
) )
847 return wxString::Format
857 bool wxIPV4address::BroadcastAddress()
859 return GetImpl().SetToBroadcastAddress();
864 // ---------------------------------------------------------------------------
866 // ---------------------------------------------------------------------------
868 void wxIPV6address::DoInitImpl()
870 m_impl
->CreateINET6();
873 bool wxIPV6address::Hostname(unsigned char addr
[16])
875 unsigned short wk
[8];
876 for ( int i
= 0; i
< 8; ++i
)
880 wk
[i
] |= addr
[2*i
+1];
887 "%x:%x:%x:%x:%x:%x:%x:%x",
888 wk
[0], wk
[1], wk
[2], wk
[3], wk
[4], wk
[5], wk
[6], wk
[7]
893 bool wxIPV6address::IsLocalHost() const
895 if ( Hostname() == "localhost" )
898 wxString addr
= IPAddress();
899 return addr
== wxT("::1") ||
900 addr
== wxT("0:0:0:0:0:0:0:1") ||
901 addr
== wxT("::ffff:127.0.0.1");
904 wxString
wxIPV6address::IPAddress() const
912 if ( !GetImpl().GetHostAddress(&u
.addr6
) )
915 const wxUint8
* const addr
= u
.bytes
;
919 prefix_zero_count
= 0;
920 for ( i
= 0; i
< 8; ++i
)
922 words
[i
] = addr
[i
*2];
924 words
[i
] |= addr
[i
*2+1];
925 if ( i
== prefix_zero_count
&& words
[i
] == 0 )
930 if ( prefix_zero_count
== 8 )
932 result
= wxT( "::" );
934 else if ( prefix_zero_count
== 6 && words
[5] == 0xFFFF )
937 result
.Printf("::ffff:%d.%d.%d.%d",
938 addr
[12], addr
[13], addr
[14], addr
[15]);
943 for ( i
= prefix_zero_count
; i
< 8; ++i
)
945 result
+= wxString::Format(":%x", words
[i
]);
954 #ifdef wxHAS_UNIX_DOMAIN_SOCKETS
956 // ---------------------------------------------------------------------------
958 // ---------------------------------------------------------------------------
960 wxSockAddressImpl
& wxUNIXaddress::GetUNIX()
962 if ( m_impl
->GetFamily() == wxSockAddressImpl::FAMILY_UNSPEC
)
963 m_impl
->CreateUnix();
968 void wxUNIXaddress::Filename(const wxString
& fname
)
970 GetUNIX().SetPath(fname
);
973 wxString
wxUNIXaddress::Filename() const
975 return GetUNIX().GetPath();
978 #endif // wxHAS_UNIX_DOMAIN_SOCKETS
980 #endif // wxUSE_SOCKETS