]>
git.saurik.com Git - wxWidgets.git/blob - src/common/sckaddr.cpp
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"
34 #include "wx/thread.h"
40 #if !defined(__MWERKS__)
45 #include "wx/socket.h"
46 #include "wx/sckaddr.h"
47 #include "wx/private/socket.h"
48 #include "wx/private/sckaddr.h"
52 #if defined(__UNIX__) && !defined(__CYGWIN__)
54 #include <arpa/inet.h>
58 #define INADDR_NONE INADDR_ANY
61 // ----------------------------------------------------------------------------
63 // ----------------------------------------------------------------------------
65 IMPLEMENT_ABSTRACT_CLASS(wxSockAddress
, wxObject
)
66 IMPLEMENT_ABSTRACT_CLASS(wxIPaddress
, wxSockAddress
)
67 IMPLEMENT_DYNAMIC_CLASS(wxIPV4address
, wxIPaddress
)
69 IMPLEMENT_DYNAMIC_CLASS(wxIPV6address
, wxIPaddress
)
71 #if defined(__UNIX__) && !defined(__WINDOWS__) && !defined(__WINE__)
72 IMPLEMENT_DYNAMIC_CLASS(wxUNIXaddress
, wxSockAddress
)
75 // ============================================================================
76 // implementation of thread-safe/reentrant functions if they're missing
77 // ============================================================================
79 // TODO: use POSIX getaddrinfo() (also available in Winsock 2) for simplicity
80 // and to use the same code for IPv4 and IPv6 support
83 #define HAVE_INET_ADDR
85 #ifndef HAVE_GETHOSTBYNAME
86 #define HAVE_GETHOSTBYNAME
88 #ifndef HAVE_GETSERVBYNAME
89 #define HAVE_GETSERVBYNAME
92 // under MSW getxxxbyname() functions are MT-safe (but not reentrant) so
93 // we don't need to serialize calls to them
94 #define wxHAS_MT_SAFE_GETBY_FUNCS
97 // this header does dynamic dispatching of getaddrinfo/freeaddrinfo()
98 // by implementing them in its own code if the system versions are not
99 // available (as is the case for anything < XP)
101 // NB: if this is not available for the other compilers (so far tested
102 // with MSVC only) we should just use wxDynamicLibrary "manually"
104 // disable a warning occurring in Microsoft own version of this file
105 #pragma warning(disable:4706)
109 #pragma warning(default:4706)
114 // we assume that we have gethostbyaddr_r() if and only if we have
115 // gethostbyname_r() and that it uses the similar conventions to it (see
116 // comment in configure)
117 #define HAVE_GETHOSTBYADDR HAVE_GETHOSTBYNAME
118 #ifdef HAVE_FUNC_GETHOSTBYNAME_R_3
119 #define HAVE_FUNC_GETHOSTBYADDR_R_3
121 #ifdef HAVE_FUNC_GETHOSTBYNAME_R_5
122 #define HAVE_FUNC_GETHOSTBYADDR_R_5
124 #ifdef HAVE_FUNC_GETHOSTBYNAME_R_6
125 #define HAVE_FUNC_GETHOSTBYADDR_R_6
128 // the _r functions need the extra buffer parameter but unfortunately its type
129 // differs between different systems and for the systems which use opaque
130 // structs for it (at least AIX and OpenBSD) it must be zero-filled before
131 // being passed to the system functions
132 #ifdef HAVE_FUNC_GETHOSTBYNAME_R_3
133 struct wxGethostBuf
: hostent_data
137 memset(this, 0, sizeof(hostent_data
));
141 typedef char wxGethostBuf
[1024];
144 #ifdef HAVE_FUNC_GETSERVBYNAME_R_4
145 struct wxGetservBuf
: servent_data
149 memset(this, 0, sizeof(servent_data
));
153 typedef char wxGetservBuf
[1024];
156 #if defined(wxHAS_MT_SAFE_GETBY_FUNCS) || !wxUSE_THREADS
157 #define wxLOCK_GETBY_MUTEX(name)
158 #else // may need mutexes to protect getxxxbyxxx() calls
159 #if defined(HAVE_GETHOSTBYNAME) || \
160 defined(HAVE_GETHOSTBYADDR) || \
161 defined(HAVE_GETSERVBYNAME)
162 #include "wx/thread.h"
166 // these mutexes are used to serialize
167 wxMutex nameLock
, // gethostbyname()
168 addrLock
, // gethostbyaddr()
169 servLock
; // getservbyname()
172 #define wxLOCK_GETBY_MUTEX(name) wxMutexLocker locker(name ## Lock)
173 #endif // we don't have _r functions
174 #endif // wxUSE_THREADS
179 #if defined(HAVE_GETHOSTBYNAME)
180 hostent
*deepCopyHostent(hostent
*h
,
186 /* copy old structure */
187 memcpy(h
, he
, sizeof(hostent
));
190 int len
= strlen(h
->h_name
);
196 memcpy(buffer
, h
->h_name
, len
);
200 /* track position in the buffer */
203 /* reuse len to store address length */
206 /* ensure pointer alignment */
207 unsigned int misalign
= sizeof(char *) - pos%sizeof
(char *);
208 if(misalign
< sizeof(char *))
211 /* leave space for pointer list */
212 char **p
= h
->h_addr_list
, **q
;
213 char **h_addr_list
= (char **)(buffer
+ pos
);
215 pos
+= sizeof(char *);
217 /* copy addresses and fill new pointer list */
218 for (p
= h
->h_addr_list
, q
= h_addr_list
; *p
!= 0; p
++, q
++)
220 if (size
< pos
+ len
)
225 memcpy(buffer
+ pos
, *p
, len
); /* copy content */
226 *q
= buffer
+ pos
; /* set copied pointer to copied content */
229 *++q
= 0; /* null terminate the pointer list */
230 h
->h_addr_list
= h_addr_list
; /* copy pointer to pointers */
232 /* ensure word alignment of pointers */
233 misalign
= sizeof(char *) - pos%sizeof
(char *);
234 if(misalign
< sizeof(char *))
237 /* leave space for pointer list */
239 char **h_aliases
= (char **)(buffer
+ pos
);
241 pos
+= sizeof(char *);
243 /* copy aliases and fill new pointer list */
244 for (p
= h
->h_aliases
, q
= h_aliases
; *p
!= 0; p
++, q
++)
247 if (size
<= pos
+ len
)
252 memcpy(buffer
+ pos
, *p
, len
); /* copy content */
253 buffer
[pos
+ len
] = '\0';
254 *q
= buffer
+ pos
; /* set copied pointer to copied content */
257 *++q
= 0; /* null terminate the pointer list */
258 h
->h_aliases
= h_aliases
; /* copy pointer to pointers */
262 #endif // HAVE_GETHOSTBYNAME
264 hostent
*wxGethostbyname_r(const char *hostname
,
271 #if defined(HAVE_FUNC_GETHOSTBYNAME_R_6)
272 gethostbyname_r(hostname
, h
, buffer
, size
, &he
, err
);
273 #elif defined(HAVE_FUNC_GETHOSTBYNAME_R_5)
274 he
= gethostbyname_r(hostname
, h
, buffer
, size
, err
);
275 #elif defined(HAVE_FUNC_GETHOSTBYNAME_R_3)
277 *err
= gethostbyname_r(hostname
, h
, &buffer
);
279 #elif defined(HAVE_GETHOSTBYNAME)
280 wxLOCK_GETBY_MUTEX(name
);
282 he
= gethostbyname(hostname
);
286 he
= deepCopyHostent(h
, he
, buffer
, size
, err
);
288 #error "No gethostbyname[_r]()"
294 hostent
*wxGethostbyaddr_r(const char *addr_buf
,
303 #if defined(HAVE_FUNC_GETHOSTBYADDR_R_6)
304 gethostbyaddr_r(addr_buf
, buf_size
, proto
, h
, buffer
, size
, &he
, err
);
305 #elif defined(HAVE_FUNC_GETHOSTBYADDR_R_5)
306 he
= gethostbyaddr_r(addr_buf
, buf_size
, proto
, h
, buffer
, size
, err
);
307 #elif defined(HAVE_FUNC_GETHOSTBYADDR_R_3)
309 *err
= gethostbyaddr_r(addr_buf
, buf_size
, proto
, h
, &buffer
);
311 #elif defined(HAVE_GETHOSTBYADDR)
312 wxLOCK_GETBY_MUTEX(addr
);
314 he
= gethostbyaddr(addr_buf
, buf_size
, proto
);
318 he
= deepCopyHostent(h
, he
, buffer
, size
, err
);
320 #error "No gethostbyaddr[_r]()"
326 #if defined(HAVE_GETSERVBYNAME)
327 servent
*deepCopyServent(servent
*s
,
332 /* copy plain old structure */
333 memcpy(s
, se
, sizeof(servent
));
336 int len
= strlen(s
->s_name
);
341 memcpy(buffer
, s
->s_name
, len
);
345 /* track position in the buffer */
349 len
= strlen(s
->s_proto
);
350 if (pos
+ len
>= size
)
354 memcpy(buffer
+ pos
, s
->s_proto
, len
);
355 buffer
[pos
+ len
] = '\0';
356 s
->s_proto
= buffer
+ pos
;
358 /* track position in the buffer */
361 /* ensure pointer alignment */
362 unsigned int misalign
= sizeof(char *) - pos%sizeof
(char *);
363 if(misalign
< sizeof(char *))
366 /* leave space for pointer list */
367 char **p
= s
->s_aliases
, **q
;
368 char **s_aliases
= (char **)(buffer
+ pos
);
370 pos
+= sizeof(char *);
372 /* copy addresses and fill new pointer list */
373 for (p
= s
->s_aliases
, q
= s_aliases
; *p
!= 0; p
++, q
++){
375 if (size
<= pos
+ len
)
379 memcpy(buffer
+ pos
, *p
, len
); /* copy content */
380 buffer
[pos
+ len
] = '\0';
381 *q
= buffer
+ pos
; /* set copied pointer to copied content */
384 *++q
= 0; /* null terminate the pointer list */
385 s
->s_aliases
= s_aliases
; /* copy pointer to pointers */
388 #endif // HAVE_GETSERVBYNAME
390 servent
*wxGetservbyname_r(const char *port
,
391 const char *protocol
,
393 wxGetservBuf
& buffer
,
397 #if defined(HAVE_FUNC_GETSERVBYNAME_R_6)
398 getservbyname_r(port
, protocol
, serv
, buffer
, size
, &se
);
399 #elif defined(HAVE_FUNC_GETSERVBYNAME_R_5)
400 se
= getservbyname_r(port
, protocol
, serv
, buffer
, size
);
401 #elif defined(HAVE_FUNC_GETSERVBYNAME_R_4)
403 if ( getservbyname_r(port
, protocol
, serv
, &buffer
) != 0 )
405 #elif defined(HAVE_GETSERVBYNAME)
406 wxLOCK_GETBY_MUTEX(serv
);
408 se
= getservbyname(port
, protocol
);
410 se
= deepCopyServent(serv
, se
, buffer
, size
);
412 #error "No getservbyname[_r]()"
417 } // anonymous namespace
419 // ============================================================================
420 // wxSockAddressImpl implementation
421 // ============================================================================
423 // FIXME-VC6: helper macros to call Alloc/Get() hiding the ugly dummy argument
424 #define ALLOC(T) Alloc(static_cast<T *>(NULL))
425 #define GET(T) Get(static_cast<T *>(NULL))
427 // ----------------------------------------------------------------------------
428 // INET or INET6 address family
429 // ----------------------------------------------------------------------------
431 wxString
wxSockAddressImpl::GetHostName() const
437 if ( m_family
== FAMILY_INET6
)
439 sockaddr_in6
* const addr6
= GET(sockaddr_in6
);
440 addrbuf
= &addr6
->sin6_addr
;
441 addrbuflen
= sizeof(addr6
->sin6_addr
);
446 sockaddr_in
* const addr
= GET(sockaddr_in
);
450 addrbuf
= &addr
->sin_addr
;
451 addrbuflen
= sizeof(addr
->sin_addr
);
457 if ( !wxGethostbyaddr_r
459 static_cast<const char *>(addrbuf
),
471 return wxString::FromUTF8(he
.h_name
);
474 bool wxSockAddressImpl::SetPortName(const wxString
& name
, const char *protocol
)
476 // test whether it's a number first
478 if ( name
.ToULong(&port
) )
483 else // it's a service name
487 if ( !wxGetservbyname_r(name
.utf8_str(), protocol
, &se
,
488 buffer
, sizeof(buffer
)) )
491 // s_port is in network byte order and SetPort() uses the host byte
492 // order and we prefer to reuse it from here instead of assigning to
494 port
= ntohs(se
.s_port
);
497 return SetPort(port
);
500 // ----------------------------------------------------------------------------
501 // INET address family
502 // ----------------------------------------------------------------------------
504 void wxSockAddressImpl::CreateINET()
506 wxASSERT_MSG( Is(FAMILY_UNSPEC
), "recreating address as different type?" );
508 m_family
= FAMILY_INET
;
509 sockaddr_in
* const addr
= ALLOC(sockaddr_in
);
510 addr
->sin_family
= FAMILY_INET
;
513 bool wxSockAddressImpl::SetHostName4(const wxString
& name
)
515 sockaddr_in
* const addr
= GET(sockaddr_in
);
519 const wxScopedCharBuffer
namebuf(name
.utf8_str());
521 // first check if this is an address in quad dotted notation
522 #if defined(HAVE_INET_ATON)
523 if ( inet_aton(namebuf
, &addr
->sin_addr
) )
525 #elif defined(HAVE_INET_ADDR)
526 addr
->sin_addr
.s_addr
= inet_addr(namebuf
);
527 if ( addr
->sin_addr
.s_addr
!= INADDR_NONE
)
530 #error "Neither inet_aton() nor inet_addr() is available?"
533 // it's a host name, resolve it
537 if ( !wxGethostbyname_r(namebuf
, &he
, buffer
, sizeof(buffer
), &err
) )
540 addr
->sin_addr
.s_addr
= ((in_addr
*)he
.h_addr
)->s_addr
;
544 bool wxSockAddressImpl::GetHostAddress(wxUint32
*address
) const
546 sockaddr_in
* const addr
= GET(sockaddr_in
);
550 *address
= ntohl(addr
->sin_addr
.s_addr
);
555 bool wxSockAddressImpl::SetHostAddress(wxUint32 address
)
557 sockaddr_in
* const addr
= GET(sockaddr_in
);
561 addr
->sin_addr
.s_addr
= htonl(address
);
566 wxUint16
wxSockAddressImpl::GetPort4() const
568 sockaddr_in
* const addr
= GET(sockaddr_in
);
572 return ntohs(addr
->sin_port
);
575 bool wxSockAddressImpl::SetPort4(wxUint16 port
)
577 sockaddr_in
* const addr
= GET(sockaddr_in
);
581 addr
->sin_port
= htons(port
);
588 // ----------------------------------------------------------------------------
589 // INET6 address family
590 // ----------------------------------------------------------------------------
592 void wxSockAddressImpl::CreateINET6()
594 wxASSERT_MSG( Is(FAMILY_UNSPEC
), "recreating address as different type?" );
596 m_family
= FAMILY_INET6
;
597 sockaddr_in6
* const addr
= ALLOC(sockaddr_in6
);
598 addr
->sin6_family
= FAMILY_INET6
;
601 bool wxSockAddressImpl::SetHostName6(const wxString
& hostname
)
603 sockaddr_in6
* const addr
= GET(sockaddr_in6
);
608 memset(&hints
, 0, sizeof(hints
));
609 hints
.ai_family
= AF_INET6
;
611 addrinfo
*info
= NULL
;
612 int rc
= getaddrinfo(hostname
.utf8_str(), NULL
, &hints
, &info
);
615 // use gai_strerror()?
619 wxCHECK_MSG( info
, false, "should have info on success" );
621 wxASSERT_MSG( int(info
->ai_addrlen
) == m_len
, "unexpected address length" );
623 memcpy(addr
, info
->ai_addr
, info
->ai_addrlen
);
629 bool wxSockAddressImpl::GetHostAddress(in6_addr
*address
) const
631 sockaddr_in6
* const addr
= GET(sockaddr_in6
);
635 *address
= addr
->sin6_addr
;
640 bool wxSockAddressImpl::SetHostAddress(const in6_addr
& address
)
642 sockaddr_in6
* const addr
= GET(sockaddr_in6
);
646 addr
->sin6_addr
= address
;
651 wxUint16
wxSockAddressImpl::GetPort6() const
653 sockaddr_in6
* const addr
= GET(sockaddr_in6
);
657 return ntohs(addr
->sin6_port
);
660 bool wxSockAddressImpl::SetPort6(wxUint16 port
)
662 sockaddr_in6
* const addr
= GET(sockaddr_in6
);
666 addr
->sin6_port
= htons(port
);
671 bool wxSockAddressImpl::SetToAnyAddress6()
673 static const in6_addr any
= IN6ADDR_ANY_INIT
;
675 return SetHostAddress(any
);
680 #ifdef wxHAS_UNIX_DOMAIN_SOCKETS
682 // ----------------------------------------------------------------------------
683 // Unix address family
684 // ----------------------------------------------------------------------------
686 #ifndef UNIX_PATH_MAX
687 #define UNIX_PATH_MAX (WXSIZEOF(((sockaddr_un *)NULL)->sun_path))
690 void wxSockAddressImpl::CreateUnix()
692 wxASSERT_MSG( Is(FAMILY_UNSPEC
), "recreating address as different type?" );
694 m_family
= FAMILY_UNIX
;
695 sockaddr_un
* const addr
= ALLOC(sockaddr_un
);
696 addr
->sun_family
= FAMILY_UNIX
;
697 addr
->sun_path
[0] = '\0';
700 bool wxSockAddressImpl::SetPath(const wxString
& path
)
702 sockaddr_un
* const addr
= GET(sockaddr_un
);
706 const wxScopedCharBuffer
buf(path
.utf8_str());
707 if ( strlen(buf
) >= UNIX_PATH_MAX
)
710 wxStrlcpy(addr
->sun_path
, buf
, UNIX_PATH_MAX
);
715 wxString
wxSockAddressImpl::GetPath() const
717 sockaddr_un
* const addr
= GET(sockaddr_un
);
721 return wxString::FromUTF8(addr
->sun_path
);
724 #endif // wxHAS_UNIX_DOMAIN_SOCKETS
729 // ----------------------------------------------------------------------------
731 // ----------------------------------------------------------------------------
733 const sockaddr
*wxSockAddress::GetAddressData() const
735 return GetAddress().GetAddr();
738 int wxSockAddress::GetAddressDataLen() const
740 return GetAddress().GetLen();
743 void wxSockAddress::Init()
745 if ( wxIsMainThread() && !wxSocketBase::IsInitialized() )
747 // we must do it before using any socket functions
748 (void)wxSocketBase::Initialize();
752 wxSockAddress::wxSockAddress()
756 m_impl
= new wxSockAddressImpl();
759 wxSockAddress::wxSockAddress(const wxSockAddress
& other
)
764 m_impl
= new wxSockAddressImpl(*other
.m_impl
);
767 wxSockAddress::~wxSockAddress()
772 void wxSockAddress::SetAddress(const wxSockAddressImpl
& address
)
774 if ( &address
!= m_impl
)
777 m_impl
= new wxSockAddressImpl(address
);
781 wxSockAddress
& wxSockAddress::operator=(const wxSockAddress
& addr
)
783 SetAddress(addr
.GetAddress());
788 void wxSockAddress::Clear()
793 // ----------------------------------------------------------------------------
795 // ----------------------------------------------------------------------------
797 wxSockAddressImpl
& wxIPaddress::GetImpl()
799 if ( m_impl
->GetFamily() == wxSockAddressImpl::FAMILY_UNSPEC
)
800 m_impl
->CreateINET();
805 bool wxIPaddress::Hostname(const wxString
& name
)
807 wxCHECK_MSG( !name
.empty(), false, "empty host name is invalid" );
809 m_origHostname
= name
;
811 return GetImpl().SetHostName(name
);
814 bool wxIPaddress::Service(const wxString
& name
)
816 return GetImpl().SetPortName(name
, "tcp");
819 bool wxIPaddress::Service(unsigned short port
)
821 return GetImpl().SetPort(port
);
824 bool wxIPaddress::LocalHost()
826 return Hostname("localhost");
829 wxString
wxIPaddress::Hostname() const
831 return GetImpl().GetHostName();
834 unsigned short wxIPaddress::Service() const
836 return GetImpl().GetPort();
839 bool wxIPaddress::operator==(const wxIPaddress
& addr
) const
841 return Hostname().Cmp(addr
.Hostname()) == 0 &&
842 Service() == addr
.Service();
845 bool wxIPaddress::AnyAddress()
847 return GetImpl().SetToAnyAddress();
850 // ----------------------------------------------------------------------------
852 // ----------------------------------------------------------------------------
854 void wxIPV4address::DoInitImpl()
856 m_impl
->CreateINET();
859 bool wxIPV4address::Hostname(unsigned long addr
)
861 if ( !GetImpl().SetHostAddress(addr
) )
863 m_origHostname
.clear();
867 m_origHostname
= Hostname();
871 bool wxIPV4address::IsLocalHost() const
873 return Hostname() == "localhost" || IPAddress() == "127.0.0.1";
876 wxString
wxIPV4address::IPAddress() const
879 if ( !GetImpl().GetHostAddress(&addr
) )
882 return wxString::Format
892 bool wxIPV4address::BroadcastAddress()
894 return GetImpl().SetToBroadcastAddress();
899 // ---------------------------------------------------------------------------
901 // ---------------------------------------------------------------------------
903 void wxIPV6address::DoInitImpl()
905 m_impl
->CreateINET6();
908 bool wxIPV6address::Hostname(unsigned char addr
[16])
910 unsigned short wk
[8];
911 for ( int i
= 0; i
< 8; ++i
)
915 wk
[i
] |= addr
[2*i
+1];
922 "%x:%x:%x:%x:%x:%x:%x:%x",
923 wk
[0], wk
[1], wk
[2], wk
[3], wk
[4], wk
[5], wk
[6], wk
[7]
928 bool wxIPV6address::IsLocalHost() const
930 if ( Hostname() == "localhost" )
933 wxString addr
= IPAddress();
934 return addr
== wxT("::1") ||
935 addr
== wxT("0:0:0:0:0:0:0:1") ||
936 addr
== wxT("::ffff:127.0.0.1");
939 wxString
wxIPV6address::IPAddress() const
947 if ( !GetImpl().GetHostAddress(&u
.addr6
) )
950 const wxUint8
* const addr
= u
.bytes
;
954 prefix_zero_count
= 0;
955 for ( i
= 0; i
< 8; ++i
)
957 words
[i
] = addr
[i
*2];
959 words
[i
] |= addr
[i
*2+1];
960 if ( i
== prefix_zero_count
&& words
[i
] == 0 )
965 if ( prefix_zero_count
== 8 )
967 result
= wxT( "::" );
969 else if ( prefix_zero_count
== 6 && words
[5] == 0xFFFF )
972 result
.Printf("::ffff:%d.%d.%d.%d",
973 addr
[12], addr
[13], addr
[14], addr
[15]);
978 for ( i
= prefix_zero_count
; i
< 8; ++i
)
980 result
+= wxString::Format(":%x", words
[i
]);
989 #ifdef wxHAS_UNIX_DOMAIN_SOCKETS
991 // ---------------------------------------------------------------------------
993 // ---------------------------------------------------------------------------
995 wxSockAddressImpl
& wxUNIXaddress::GetUNIX()
997 if ( m_impl
->GetFamily() == wxSockAddressImpl::FAMILY_UNSPEC
)
998 m_impl
->CreateUnix();
1003 void wxUNIXaddress::Filename(const wxString
& fname
)
1005 GetUNIX().SetPath(fname
);
1008 wxString
wxUNIXaddress::Filename() const
1010 return GetUNIX().GetPath();
1013 #endif // wxHAS_UNIX_DOMAIN_SOCKETS
1015 #endif // wxUSE_SOCKETS