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
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 // we assume that we have gethostbyaddr_r() if and only if we have
91 // gethostbyname_r() and that it uses the similar conventions to it (see
92 // comment in configure)
93 #define HAVE_GETHOSTBYADDR HAVE_GETHOSTBYNAME
94 #ifdef HAVE_FUNC_GETHOSTBYNAME_R_3
95 #define HAVE_FUNC_GETHOSTBYADDR_R_3
97 #ifdef HAVE_FUNC_GETHOSTBYNAME_R_5
98 #define HAVE_FUNC_GETHOSTBYADDR_R_5
100 #ifdef HAVE_FUNC_GETHOSTBYNAME_R_6
101 #define HAVE_FUNC_GETHOSTBYADDR_R_6
104 // the _r functions need the extra buffer parameter but unfortunately its type
105 // differs between different systems
106 #ifdef HAVE_FUNC_GETHOSTBYNAME_R_3
107 typedef hostent_data wxGethostBuf
;
109 typedef char wxGethostBuf
[1024];
112 #ifdef HAVE_FUNC_GETSERVBYNAME_R_3
113 typedef servent_data wxGetservBuf
;
115 typedef char wxGetservBuf
[1024];
118 #ifdef wxHAS_MT_SAFE_GETBY_FUNCS
119 #define wxLOCK_GETBY_MUTEX(name)
120 #else // may need mutexes to protect getxxxbyxxx() calls
121 #if defined(HAVE_GETHOSTBYNAME) || \
122 defined(HAVE_GETHOSTBYADDR) || \
123 defined(HAVE_GETSERVBYNAME)
124 #include "wx/thread.h"
128 // these mutexes are used to serialize
129 wxMutex nameLock
, // gethostbyname()
130 addrLock
, // gethostbyaddr()
131 servLock
; // getservbyname()
134 #define wxLOCK_GETBY_MUTEX(name) wxMutexLocker locker(name ## Lock)
135 #endif // we don't have _r functions
136 #endif // wxUSE_THREADS
141 #if defined(HAVE_GETHOSTBYNAME)
142 hostent
*deepCopyHostent(hostent
*h
,
148 /* copy old structure */
149 memcpy(h
, he
, sizeof(hostent
));
152 int len
= strlen(h
->h_name
);
158 memcpy(buffer
, h
->h_name
, len
);
162 /* track position in the buffer */
165 /* reuse len to store address length */
168 /* ensure pointer alignment */
169 unsigned int misalign
= sizeof(char *) - pos%sizeof
(char *);
170 if(misalign
< sizeof(char *))
173 /* leave space for pointer list */
174 char **p
= h
->h_addr_list
, **q
;
175 char **h_addr_list
= (char **)(buffer
+ pos
);
177 pos
+= sizeof(char *);
179 /* copy addresses and fill new pointer list */
180 for (p
= h
->h_addr_list
, q
= h_addr_list
; *p
!= 0; p
++, q
++)
182 if (size
< pos
+ len
)
187 memcpy(buffer
+ pos
, *p
, len
); /* copy content */
188 *q
= buffer
+ pos
; /* set copied pointer to copied content */
191 *++q
= 0; /* null terminate the pointer list */
192 h
->h_addr_list
= h_addr_list
; /* copy pointer to pointers */
194 /* ensure word alignment of pointers */
195 misalign
= sizeof(char *) - pos%sizeof
(char *);
196 if(misalign
< sizeof(char *))
199 /* leave space for pointer list */
201 char **h_aliases
= (char **)(buffer
+ pos
);
203 pos
+= sizeof(char *);
205 /* copy aliases and fill new pointer list */
206 for (p
= h
->h_aliases
, q
= h_aliases
; *p
!= 0; p
++, q
++)
209 if (size
<= pos
+ len
)
214 memcpy(buffer
+ pos
, *p
, len
); /* copy content */
215 buffer
[pos
+ len
] = '\0';
216 *q
= buffer
+ pos
; /* set copied pointer to copied content */
219 *++q
= 0; /* null terminate the pointer list */
220 h
->h_aliases
= h_aliases
; /* copy pointer to pointers */
224 #endif // HAVE_GETHOSTBYNAME
226 hostent
*wxGethostbyname_r(const char *hostname
,
233 #if defined(HAVE_FUNC_GETHOSTBYNAME_R_6)
234 gethostbyname_r(hostname
, h
, buffer
, size
, &he
, err
);
235 #elif defined(HAVE_FUNC_GETHOSTBYNAME_R_5)
236 he
= gethostbyname_r(hostname
, h
, buffer
, size
, err
);
237 #elif defined(HAVE_FUNC_GETHOSTBYNAME_R_3)
238 he
= gethostbyname_r(hostname
, h
, &buffer
);
240 #elif defined(HAVE_GETHOSTBYNAME)
241 wxLOCK_GETBY_MUTEX(name
);
243 he
= gethostbyname(hostname
);
247 he
= deepCopyHostent(h
, he
, buffer
, size
, err
);
249 #error "No gethostbyname[_r]()"
255 hostent
*wxGethostbyaddr_r(const char *addr_buf
,
264 #if defined(HAVE_FUNC_GETHOSTBYADDR_R_6)
265 gethostbyaddr_r(addr_buf
, buf_size
, proto
, h
, buffer
, size
, &he
, err
);
266 #elif defined(HAVE_FUNC_GETHOSTBYADDR_R_5)
267 he
= gethostbyaddr_r(addr_buf
, buf_size
, proto
, h
, buffer
, size
, err
);
268 #elif defined(HAVE_FUNC_GETHOSTBYADDR_R_3)
269 he
= gethostbyaddr_r(addr_buf
, buf_size
, proto
, h
, buffer
);
271 #elif defined(HAVE_GETHOSTBYADDR)
272 wxLOCK_GETBY_MUTEX(addr
);
274 he
= gethostbyaddr(addr_buf
, buf_size
, proto
);
278 he
= deepCopyHostent(h
, he
, buffer
, size
, err
);
280 #error "No gethostbyaddr[_r]()"
286 #if defined(HAVE_GETSERVBYNAME)
287 servent
*deepCopyServent(servent
*s
,
292 /* copy plain old structure */
293 memcpy(s
, se
, sizeof(servent
));
296 int len
= strlen(s
->s_name
);
301 memcpy(buffer
, s
->s_name
, len
);
305 /* track position in the buffer */
309 len
= strlen(s
->s_proto
);
310 if (pos
+ len
>= size
)
314 memcpy(buffer
+ pos
, s
->s_proto
, len
);
315 buffer
[pos
+ len
] = '\0';
316 s
->s_proto
= buffer
+ pos
;
318 /* track position in the buffer */
321 /* ensure pointer alignment */
322 unsigned int misalign
= sizeof(char *) - pos%sizeof
(char *);
323 if(misalign
< sizeof(char *))
326 /* leave space for pointer list */
327 char **p
= s
->s_aliases
, **q
;
328 char **s_aliases
= (char **)(buffer
+ pos
);
330 pos
+= sizeof(char *);
332 /* copy addresses and fill new pointer list */
333 for (p
= s
->s_aliases
, q
= s_aliases
; *p
!= 0; p
++, q
++){
335 if (size
<= pos
+ len
)
339 memcpy(buffer
+ pos
, *p
, len
); /* copy content */
340 buffer
[pos
+ len
] = '\0';
341 *q
= buffer
+ pos
; /* set copied pointer to copied content */
344 *++q
= 0; /* null terminate the pointer list */
345 s
->s_aliases
= s_aliases
; /* copy pointer to pointers */
348 #endif // HAVE_GETSERVBYNAME
350 servent
*wxGetservbyname_r(const char *port
,
351 const char *protocol
,
357 #if defined(HAVE_FUNC_GETSERVBYNAME_R_6)
358 getservbyname_r(port
, protocol
, serv
, buffer
, size
, &se
);
359 #elif defined(HAVE_FUNC_GETSERVBYNAME_R_5)
360 se
= getservbyname_r(port
, protocol
, serv
, buffer
, size
);
361 #elif defined(HAVE_FUNC_GETSERVBYNAME_R_4)
362 se
= getservbyname_r(port
, protocol
, serv
, &buffer
);
363 #elif defined(HAVE_GETSERVBYNAME)
364 wxLOCK_GETBY_MUTEX(serv
);
366 se
= getservbyname(port
, protocol
);
368 se
= deepCopyServent(serv
, se
, buffer
, size
);
370 #error "No getservbyname[_r]()"
375 } // anonymous namespace
377 // ============================================================================
378 // wxSockAddressImpl implementation
379 // ============================================================================
381 // FIXME-VC6: helper macros to call Alloc/Get() hiding the ugly dummy argument
382 #define ALLOC(T) Alloc(static_cast<T *>(NULL))
383 #define GET(T) Get(static_cast<T *>(NULL))
385 // ----------------------------------------------------------------------------
386 // INET or INET6 address family
387 // ----------------------------------------------------------------------------
389 wxString
wxSockAddressImpl::GetHostName() const
395 if ( m_family
== FAMILY_INET6
)
397 sockaddr_in6
* const addr6
= GET(sockaddr_in6
);
398 addrbuf
= &addr6
->sin6_addr
;
399 addrbuflen
= sizeof(addr6
->sin6_addr
);
404 sockaddr_in
* const addr
= GET(sockaddr_in
);
408 addrbuf
= &addr
->sin_addr
;
409 addrbuflen
= sizeof(addr
->sin_addr
);
415 if ( !wxGethostbyaddr_r
417 static_cast<const char *>(addrbuf
),
429 return wxString::FromUTF8(he
.h_name
);
432 bool wxSockAddressImpl::SetPortName(const wxString
& name
, const char *protocol
)
434 // test whether it's a number first
436 if ( name
.ToULong(&port
) )
441 else // it's a service name
445 if ( !wxGetservbyname_r(name
.utf8_str(), protocol
, &se
,
446 buffer
, sizeof(buffer
)) )
449 // s_port is in network byte order and SetPort() uses the host byte
450 // order and we prefer to reuse it from here instead of assigning to
452 port
= ntohs(se
.s_port
);
455 return SetPort(port
);
458 // ----------------------------------------------------------------------------
459 // INET address family
460 // ----------------------------------------------------------------------------
462 void wxSockAddressImpl::CreateINET()
464 wxASSERT_MSG( Is(FAMILY_UNSPEC
), "recreating address as different type?" );
466 m_family
= FAMILY_INET
;
467 sockaddr_in
* const addr
= ALLOC(sockaddr_in
);
468 addr
->sin_family
= FAMILY_INET
;
471 bool wxSockAddressImpl::SetHostName4(const wxString
& name
)
473 sockaddr_in
* const addr
= GET(sockaddr_in
);
477 const wxUTF8Buf
namebuf(name
.utf8_str());
479 // first check if this is an address in quad dotted notation
480 #if defined(HAVE_INET_ATON)
481 if ( inet_aton(namebuf
, &addr
->sin_addr
) )
483 #elif defined(HAVE_INET_ADDR)
484 addr
->sin_addr
.s_addr
= inet_addr(namebuf
);
485 if ( addr
->sin_addr
.s_addr
!= INADDR_NONE
)
488 #error "Neither inet_aton() nor inet_addr() is available?"
491 // it's a host name, resolve it
495 if ( !wxGethostbyname_r(namebuf
, &he
, buffer
, sizeof(buffer
), &err
) )
498 addr
->sin_addr
.s_addr
= ((in_addr
*)he
.h_addr
)->s_addr
;
502 bool wxSockAddressImpl::GetHostAddress(wxUint32
*address
) const
504 sockaddr_in
* const addr
= GET(sockaddr_in
);
508 *address
= ntohl(addr
->sin_addr
.s_addr
);
513 bool wxSockAddressImpl::SetHostAddress(wxUint32 address
)
515 sockaddr_in
* const addr
= GET(sockaddr_in
);
519 addr
->sin_addr
.s_addr
= htonl(address
);
524 wxUint16
wxSockAddressImpl::GetPort4() const
526 sockaddr_in
* const addr
= GET(sockaddr_in
);
530 return ntohs(addr
->sin_port
);
533 bool wxSockAddressImpl::SetPort4(wxUint16 port
)
535 sockaddr_in
* const addr
= GET(sockaddr_in
);
539 addr
->sin_port
= htons(port
);
546 // ----------------------------------------------------------------------------
547 // INET6 address family
548 // ----------------------------------------------------------------------------
550 void wxSockAddressImpl::CreateINET6()
552 wxASSERT_MSG( Is(FAMILY_UNSPEC
), "recreating address as different type?" );
554 m_family
= FAMILY_INET6
;
555 sockaddr_in6
* const addr
= ALLOC(sockaddr_in6
);
556 addr
->sin6_family
= FAMILY_INET6
;
559 bool wxSockAddressImpl::SetHostName6(const wxString
& hostname
)
561 sockaddr_in6
* const addr
= GET(sockaddr_in6
);
566 memset(&hints
, 0, sizeof(hints
));
567 hints
.ai_family
= AF_INET6
;
569 addrinfo
*info
= NULL
;
570 int rc
= getaddrinfo(hostname
.utf8_str(), NULL
, &hints
, &info
);
573 // use gai_strerror()?
577 wxCHECK_MSG( info
, false, "should have info on success" );
579 wxASSERT_MSG( int(info
->ai_addrlen
) == m_len
, "unexpected address length" );
581 memcpy(addr
, info
->ai_addr
, info
->ai_addrlen
);
587 bool wxSockAddressImpl::GetHostAddress(in6_addr
*address
) const
589 sockaddr_in6
* const addr
= GET(sockaddr_in6
);
593 *address
= addr
->sin6_addr
;
598 bool wxSockAddressImpl::SetHostAddress(const in6_addr
& address
)
600 sockaddr_in6
* const addr
= GET(sockaddr_in6
);
604 addr
->sin6_addr
= address
;
609 wxUint16
wxSockAddressImpl::GetPort6() const
611 sockaddr_in6
* const addr
= GET(sockaddr_in6
);
615 return ntohs(addr
->sin6_port
);
618 bool wxSockAddressImpl::SetPort6(wxUint16 port
)
620 sockaddr_in6
* const addr
= GET(sockaddr_in6
);
624 addr
->sin6_port
= htons(port
);
629 bool wxSockAddressImpl::SetToAnyAddress6()
631 static const in6_addr any
= IN6ADDR_ANY_INIT
;
633 return SetHostAddress(any
);
638 #ifdef wxHAS_UNIX_DOMAIN_SOCKETS
640 // ----------------------------------------------------------------------------
641 // Unix address family
642 // ----------------------------------------------------------------------------
644 #ifndef UNIX_PATH_MAX
645 #define UNIX_PATH_MAX (WXSIZEOF(((sockaddr_un *)NULL)->sun_path))
648 void wxSockAddressImpl::CreateUnix()
650 wxASSERT_MSG( Is(FAMILY_UNSPEC
), "recreating address as different type?" );
652 m_family
= FAMILY_UNIX
;
653 sockaddr_un
* const addr
= ALLOC(sockaddr_un
);
654 addr
->sun_family
= FAMILY_UNIX
;
655 addr
->sun_path
[0] = '\0';
658 bool wxSockAddressImpl::SetPath(const wxString
& path
)
660 sockaddr_un
* const addr
= GET(sockaddr_un
);
664 const wxUTF8Buf
buf(path
.utf8_str());
665 if ( strlen(buf
) >= UNIX_PATH_MAX
)
668 wxStrlcpy(addr
->sun_path
, buf
, UNIX_PATH_MAX
);
673 wxString
wxSockAddressImpl::GetPath() const
675 sockaddr_un
* const addr
= GET(sockaddr_un
);
679 return wxString::FromUTF8(addr
->sun_path
);
682 #endif // wxHAS_UNIX_DOMAIN_SOCKETS
687 // ----------------------------------------------------------------------------
689 // ----------------------------------------------------------------------------
691 void wxSockAddress::Init()
693 if ( !wxSocketBase::IsInitialized() )
695 // we must do it before using any socket functions
696 (void)wxSocketBase::Initialize();
700 wxSockAddress::wxSockAddress()
704 m_impl
= new wxSockAddressImpl();
707 wxSockAddress::wxSockAddress(const wxSockAddress
& other
)
712 m_impl
= new wxSockAddressImpl(*other
.m_impl
);
715 wxSockAddress::~wxSockAddress()
720 void wxSockAddress::SetAddress(const wxSockAddressImpl
& address
)
722 if ( &address
!= m_impl
)
725 m_impl
= new wxSockAddressImpl(address
);
729 wxSockAddress
& wxSockAddress::operator=(const wxSockAddress
& addr
)
731 SetAddress(addr
.GetAddress());
736 void wxSockAddress::Clear()
741 // ----------------------------------------------------------------------------
743 // ----------------------------------------------------------------------------
745 wxSockAddressImpl
& wxIPaddress::GetImpl()
747 if ( m_impl
->GetFamily() == wxSockAddressImpl::FAMILY_UNSPEC
)
748 m_impl
->CreateINET();
753 bool wxIPaddress::Hostname(const wxString
& name
)
755 wxCHECK_MSG( !name
.empty(), false, "empty host name is invalid" );
757 m_origHostname
= name
;
759 return GetImpl().SetHostName(name
);
762 bool wxIPaddress::Service(const wxString
& name
)
764 return GetImpl().SetPortName(name
, "tcp");
767 bool wxIPaddress::Service(unsigned short port
)
769 return GetImpl().SetPort(port
);
772 bool wxIPaddress::LocalHost()
774 return Hostname("localhost");
777 wxString
wxIPaddress::Hostname() const
779 return GetImpl().GetHostName();
782 unsigned short wxIPaddress::Service() const
784 return GetImpl().GetPort();
787 bool wxIPaddress::operator==(const wxIPaddress
& addr
) const
789 return Hostname().Cmp(addr
.Hostname()) == 0 &&
790 Service() == addr
.Service();
793 bool wxIPaddress::AnyAddress()
795 return GetImpl().SetToAnyAddress();
798 // ----------------------------------------------------------------------------
800 // ----------------------------------------------------------------------------
802 void wxIPV4address::DoInitImpl()
804 m_impl
->CreateINET();
807 bool wxIPV4address::Hostname(unsigned long addr
)
809 if ( !GetImpl().SetHostAddress(addr
) )
811 m_origHostname
.clear();
815 m_origHostname
= Hostname();
819 bool wxIPV4address::IsLocalHost() const
821 return Hostname() == "localhost" || IPAddress() == "127.0.0.1";
824 wxString
wxIPV4address::IPAddress() const
827 if ( !GetImpl().GetHostAddress(&addr
) )
830 return wxString::Format
840 bool wxIPV4address::BroadcastAddress()
842 return GetImpl().SetToBroadcastAddress();
847 // ---------------------------------------------------------------------------
849 // ---------------------------------------------------------------------------
851 void wxIPV6address::DoInitImpl()
853 m_impl
->CreateINET6();
856 bool wxIPV6address::Hostname(unsigned char addr
[16])
858 unsigned short wk
[8];
859 for ( int i
= 0; i
< 8; ++i
)
863 wk
[i
] |= addr
[2*i
+1];
870 "%x:%x:%x:%x:%x:%x:%x:%x",
871 wk
[0], wk
[1], wk
[2], wk
[3], wk
[4], wk
[5], wk
[6], wk
[7]
876 bool wxIPV6address::IsLocalHost() const
878 if ( Hostname() == "localhost" )
881 wxString addr
= IPAddress();
882 return addr
== wxT("::1") ||
883 addr
== wxT("0:0:0:0:0:0:0:1") ||
884 addr
== wxT("::ffff:127.0.0.1");
887 wxString
wxIPV6address::IPAddress() const
895 if ( !GetImpl().GetHostAddress(&u
.addr6
) )
898 const wxUint8
* const addr
= u
.bytes
;
902 prefix_zero_count
= 0;
903 for ( i
= 0; i
< 8; ++i
)
905 words
[i
] = addr
[i
*2];
907 words
[i
] |= addr
[i
*2+1];
908 if ( i
== prefix_zero_count
&& words
[i
] == 0 )
913 if ( prefix_zero_count
== 8 )
915 result
= wxT( "::" );
917 else if ( prefix_zero_count
== 6 && words
[5] == 0xFFFF )
920 result
.Printf("::ffff:%d.%d.%d.%d",
921 addr
[12], addr
[13], addr
[14], addr
[15]);
926 for ( i
= prefix_zero_count
; i
< 8; ++i
)
928 result
+= wxString::Format(":%x", words
[i
]);
937 #ifdef wxHAS_UNIX_DOMAIN_SOCKETS
939 // ---------------------------------------------------------------------------
941 // ---------------------------------------------------------------------------
943 wxSockAddressImpl
& wxUNIXaddress::GetUNIX()
945 if ( m_impl
->GetFamily() == wxSockAddressImpl::FAMILY_UNSPEC
)
946 m_impl
->CreateUnix();
951 void wxUNIXaddress::Filename(const wxString
& fname
)
953 GetUNIX().SetPath(fname
);
956 wxString
wxUNIXaddress::Filename() const
958 return GetUNIX().GetPath();
961 #endif // wxHAS_UNIX_DOMAIN_SOCKETS
963 #endif // wxUSE_SOCKETS