]>
git.saurik.com Git - wxWidgets.git/blob - src/common/sckaddr.cpp
3d25f931549c73fc498321011dd903ef32bf43a3
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"
43 #include "wx/socket.h"
44 #include "wx/sckaddr.h"
45 #include "wx/private/socket.h"
46 #include "wx/private/sckaddr.h"
50 #if defined(__UNIX__) && !defined(__WXMSW__)
52 #include <arpa/inet.h>
56 #define INADDR_NONE INADDR_ANY
59 // ----------------------------------------------------------------------------
61 // ----------------------------------------------------------------------------
63 IMPLEMENT_ABSTRACT_CLASS(wxSockAddress
, wxObject
)
64 IMPLEMENT_ABSTRACT_CLASS(wxIPaddress
, wxSockAddress
)
65 IMPLEMENT_DYNAMIC_CLASS(wxIPV4address
, wxIPaddress
)
67 IMPLEMENT_DYNAMIC_CLASS(wxIPV6address
, wxIPaddress
)
69 #if defined(__UNIX__) && !defined(__WINDOWS__) && !defined(__WINE__)
70 IMPLEMENT_DYNAMIC_CLASS(wxUNIXaddress
, wxSockAddress
)
73 // ============================================================================
74 // implementation of thread-safe/reentrant functions if they're missing
75 // ============================================================================
77 // TODO: use POSIX getaddrinfo() (also available in Winsock 2) for simplicity
78 // and to use the same code for IPv4 and IPv6 support
81 #define HAVE_INET_ADDR
83 #ifndef HAVE_GETHOSTBYNAME
84 #define HAVE_GETHOSTBYNAME
86 #ifndef HAVE_GETSERVBYNAME
87 #define HAVE_GETSERVBYNAME
90 // under MSW getxxxbyname() functions are MT-safe (but not reentrant) so
91 // we don't need to serialize calls to them
92 #define wxHAS_MT_SAFE_GETBY_FUNCS
96 // this header does dynamic dispatching of getaddrinfo/freeaddrinfo()
97 // by implementing them in its own code if the system versions are
98 // not available (as is the case for anything < XP)
100 #pragma warning(disable:4706)
104 // TODO: Use wxDynamicLibrary to bind to these functions
105 // dynamically on older Windows systems, currently a program
106 // built with wxUSE_IPV6==1 won't even start there, even if
107 // it doesn't actually use the socket stuff.
108 #include <ws2tcpip.h>
111 #endif // __WINDOWS__
113 // we assume that we have gethostbyaddr_r() if and only if we have
114 // gethostbyname_r() and that it uses the similar conventions to it (see
115 // comment in configure)
116 #define HAVE_GETHOSTBYADDR HAVE_GETHOSTBYNAME
117 #ifdef HAVE_FUNC_GETHOSTBYNAME_R_3
118 #define HAVE_FUNC_GETHOSTBYADDR_R_3
120 #ifdef HAVE_FUNC_GETHOSTBYNAME_R_5
121 #define HAVE_FUNC_GETHOSTBYADDR_R_5
123 #ifdef HAVE_FUNC_GETHOSTBYNAME_R_6
124 #define HAVE_FUNC_GETHOSTBYADDR_R_6
127 // the _r functions need the extra buffer parameter but unfortunately its type
128 // differs between different systems and for the systems which use opaque
129 // structs for it (at least AIX and OpenBSD) it must be zero-filled before
130 // being passed to the system functions
131 #ifdef HAVE_FUNC_GETHOSTBYNAME_R_3
132 struct wxGethostBuf
: hostent_data
136 memset(this, 0, sizeof(hostent_data
));
140 typedef char wxGethostBuf
[1024];
143 #ifdef HAVE_FUNC_GETSERVBYNAME_R_4
144 struct wxGetservBuf
: servent_data
148 memset(this, 0, sizeof(servent_data
));
152 typedef char wxGetservBuf
[1024];
155 #if defined(wxHAS_MT_SAFE_GETBY_FUNCS) || !wxUSE_THREADS
156 #define wxLOCK_GETBY_MUTEX(name)
157 #else // may need mutexes to protect getxxxbyxxx() calls
158 #if defined(HAVE_GETHOSTBYNAME) || \
159 defined(HAVE_GETHOSTBYADDR) || \
160 defined(HAVE_GETSERVBYNAME)
161 #include "wx/thread.h"
165 // these mutexes are used to serialize
166 wxMutex nameLock
, // gethostbyname()
167 addrLock
, // gethostbyaddr()
168 servLock
; // getservbyname()
171 #define wxLOCK_GETBY_MUTEX(name) wxMutexLocker locker(name ## Lock)
172 #endif // we don't have _r functions
173 #endif // wxUSE_THREADS
178 #if defined(HAVE_GETHOSTBYNAME)
179 hostent
*deepCopyHostent(hostent
*h
,
185 /* copy old structure */
186 memcpy(h
, he
, sizeof(hostent
));
189 int len
= strlen(h
->h_name
);
195 memcpy(buffer
, h
->h_name
, len
);
199 /* track position in the buffer */
202 /* reuse len to store address length */
205 /* ensure pointer alignment */
206 unsigned int misalign
= sizeof(char *) - pos%sizeof
(char *);
207 if(misalign
< sizeof(char *))
210 /* leave space for pointer list */
211 char **p
= h
->h_addr_list
, **q
;
212 char **h_addr_list
= (char **)(buffer
+ pos
);
214 pos
+= sizeof(char *);
216 /* copy addresses and fill new pointer list */
217 for (p
= h
->h_addr_list
, q
= h_addr_list
; *p
!= 0; p
++, q
++)
219 if (size
< pos
+ len
)
224 memcpy(buffer
+ pos
, *p
, len
); /* copy content */
225 *q
= buffer
+ pos
; /* set copied pointer to copied content */
228 *++q
= 0; /* null terminate the pointer list */
229 h
->h_addr_list
= h_addr_list
; /* copy pointer to pointers */
231 /* ensure word alignment of pointers */
232 misalign
= sizeof(char *) - pos%sizeof
(char *);
233 if(misalign
< sizeof(char *))
236 /* leave space for pointer list */
238 char **h_aliases
= (char **)(buffer
+ pos
);
240 pos
+= sizeof(char *);
242 /* copy aliases and fill new pointer list */
243 for (p
= h
->h_aliases
, q
= h_aliases
; *p
!= 0; p
++, q
++)
246 if (size
<= pos
+ len
)
251 memcpy(buffer
+ pos
, *p
, len
); /* copy content */
252 buffer
[pos
+ len
] = '\0';
253 *q
= buffer
+ pos
; /* set copied pointer to copied content */
256 *++q
= 0; /* null terminate the pointer list */
257 h
->h_aliases
= h_aliases
; /* copy pointer to pointers */
261 #endif // HAVE_GETHOSTBYNAME
263 hostent
*wxGethostbyname_r(const char *hostname
,
270 #if defined(HAVE_FUNC_GETHOSTBYNAME_R_6)
271 gethostbyname_r(hostname
, h
, buffer
, size
, &he
, err
);
272 #elif defined(HAVE_FUNC_GETHOSTBYNAME_R_5)
273 he
= gethostbyname_r(hostname
, h
, buffer
, size
, err
);
274 #elif defined(HAVE_FUNC_GETHOSTBYNAME_R_3)
276 *err
= gethostbyname_r(hostname
, h
, &buffer
);
278 #elif defined(HAVE_GETHOSTBYNAME)
279 wxLOCK_GETBY_MUTEX(name
);
281 he
= gethostbyname(hostname
);
285 he
= deepCopyHostent(h
, he
, buffer
, size
, err
);
287 #error "No gethostbyname[_r]()"
293 hostent
*wxGethostbyaddr_r(const char *addr_buf
,
302 #if defined(HAVE_FUNC_GETHOSTBYADDR_R_6)
303 gethostbyaddr_r(addr_buf
, buf_size
, proto
, h
, buffer
, size
, &he
, err
);
304 #elif defined(HAVE_FUNC_GETHOSTBYADDR_R_5)
305 he
= gethostbyaddr_r(addr_buf
, buf_size
, proto
, h
, buffer
, size
, err
);
306 #elif defined(HAVE_FUNC_GETHOSTBYADDR_R_3)
308 *err
= gethostbyaddr_r(addr_buf
, buf_size
, proto
, h
, &buffer
);
310 #elif defined(HAVE_GETHOSTBYADDR)
311 wxLOCK_GETBY_MUTEX(addr
);
313 he
= gethostbyaddr(addr_buf
, buf_size
, proto
);
317 he
= deepCopyHostent(h
, he
, buffer
, size
, err
);
319 #error "No gethostbyaddr[_r]()"
325 #if defined(HAVE_GETSERVBYNAME)
326 servent
*deepCopyServent(servent
*s
,
331 /* copy plain old structure */
332 memcpy(s
, se
, sizeof(servent
));
335 int len
= strlen(s
->s_name
);
340 memcpy(buffer
, s
->s_name
, len
);
344 /* track position in the buffer */
348 len
= strlen(s
->s_proto
);
349 if (pos
+ len
>= size
)
353 memcpy(buffer
+ pos
, s
->s_proto
, len
);
354 buffer
[pos
+ len
] = '\0';
355 s
->s_proto
= buffer
+ pos
;
357 /* track position in the buffer */
360 /* ensure pointer alignment */
361 unsigned int misalign
= sizeof(char *) - pos%sizeof
(char *);
362 if(misalign
< sizeof(char *))
365 /* leave space for pointer list */
366 char **p
= s
->s_aliases
, **q
;
367 char **s_aliases
= (char **)(buffer
+ pos
);
369 pos
+= sizeof(char *);
371 /* copy addresses and fill new pointer list */
372 for (p
= s
->s_aliases
, q
= s_aliases
; *p
!= 0; p
++, q
++){
374 if (size
<= pos
+ len
)
378 memcpy(buffer
+ pos
, *p
, len
); /* copy content */
379 buffer
[pos
+ len
] = '\0';
380 *q
= buffer
+ pos
; /* set copied pointer to copied content */
383 *++q
= 0; /* null terminate the pointer list */
384 s
->s_aliases
= s_aliases
; /* copy pointer to pointers */
387 #endif // HAVE_GETSERVBYNAME
389 servent
*wxGetservbyname_r(const char *port
,
390 const char *protocol
,
392 wxGetservBuf
& buffer
,
396 #if defined(HAVE_FUNC_GETSERVBYNAME_R_6)
397 getservbyname_r(port
, protocol
, serv
, buffer
, size
, &se
);
398 #elif defined(HAVE_FUNC_GETSERVBYNAME_R_5)
399 se
= getservbyname_r(port
, protocol
, serv
, buffer
, size
);
400 #elif defined(HAVE_FUNC_GETSERVBYNAME_R_4)
402 if ( getservbyname_r(port
, protocol
, serv
, &buffer
) != 0 )
404 #elif defined(HAVE_GETSERVBYNAME)
405 wxLOCK_GETBY_MUTEX(serv
);
407 se
= getservbyname(port
, protocol
);
409 se
= deepCopyServent(serv
, se
, buffer
, size
);
411 #error "No getservbyname[_r]()"
416 } // anonymous namespace
418 // ============================================================================
419 // wxSockAddressImpl implementation
420 // ============================================================================
422 // FIXME-VC6: helper macros to call Alloc/Get() hiding the ugly dummy argument
423 #define ALLOC(T) Alloc(static_cast<T *>(NULL))
424 #define GET(T) Get(static_cast<T *>(NULL))
426 // ----------------------------------------------------------------------------
427 // INET or INET6 address family
428 // ----------------------------------------------------------------------------
430 wxString
wxSockAddressImpl::GetHostName() const
436 if ( m_family
== FAMILY_INET6
)
438 sockaddr_in6
* const addr6
= GET(sockaddr_in6
);
439 addrbuf
= &addr6
->sin6_addr
;
440 addrbuflen
= sizeof(addr6
->sin6_addr
);
445 sockaddr_in
* const addr
= GET(sockaddr_in
);
449 addrbuf
= &addr
->sin_addr
;
450 addrbuflen
= sizeof(addr
->sin_addr
);
456 if ( !wxGethostbyaddr_r
458 static_cast<const char *>(addrbuf
),
470 return wxString::FromUTF8(he
.h_name
);
473 bool wxSockAddressImpl::SetPortName(const wxString
& name
, const char *protocol
)
475 // test whether it's a number first
477 if ( name
.ToULong(&port
) )
482 else // it's a service name
486 if ( !wxGetservbyname_r(name
.utf8_str(), protocol
, &se
,
487 buffer
, sizeof(buffer
)) )
490 // s_port is in network byte order and SetPort() uses the host byte
491 // order and we prefer to reuse it from here instead of assigning to
493 port
= ntohs(se
.s_port
);
496 return SetPort(port
);
499 // ----------------------------------------------------------------------------
500 // INET address family
501 // ----------------------------------------------------------------------------
503 void wxSockAddressImpl::CreateINET()
505 wxASSERT_MSG( Is(FAMILY_UNSPEC
), "recreating address as different type?" );
507 m_family
= FAMILY_INET
;
508 sockaddr_in
* const addr
= ALLOC(sockaddr_in
);
509 addr
->sin_family
= FAMILY_INET
;
512 bool wxSockAddressImpl::SetHostName4(const wxString
& name
)
514 sockaddr_in
* const addr
= GET(sockaddr_in
);
518 const wxScopedCharBuffer
namebuf(name
.utf8_str());
520 // first check if this is an address in quad dotted notation
521 #if defined(HAVE_INET_ATON)
522 if ( inet_aton(namebuf
, &addr
->sin_addr
) )
524 #elif defined(HAVE_INET_ADDR)
525 addr
->sin_addr
.s_addr
= inet_addr(namebuf
);
526 if ( addr
->sin_addr
.s_addr
!= INADDR_NONE
)
529 #error "Neither inet_aton() nor inet_addr() is available?"
532 // it's a host name, resolve it
536 if ( !wxGethostbyname_r(namebuf
, &he
, buffer
, sizeof(buffer
), &err
) )
539 addr
->sin_addr
.s_addr
= ((in_addr
*)he
.h_addr
)->s_addr
;
543 bool wxSockAddressImpl::GetHostAddress(wxUint32
*address
) const
545 sockaddr_in
* const addr
= GET(sockaddr_in
);
549 *address
= ntohl(addr
->sin_addr
.s_addr
);
554 bool wxSockAddressImpl::SetHostAddress(wxUint32 address
)
556 sockaddr_in
* const addr
= GET(sockaddr_in
);
560 addr
->sin_addr
.s_addr
= htonl(address
);
565 wxUint16
wxSockAddressImpl::GetPort4() const
567 sockaddr_in
* const addr
= GET(sockaddr_in
);
571 return ntohs(addr
->sin_port
);
574 bool wxSockAddressImpl::SetPort4(wxUint16 port
)
576 sockaddr_in
* const addr
= GET(sockaddr_in
);
580 addr
->sin_port
= htons(port
);
587 // ----------------------------------------------------------------------------
588 // INET6 address family
589 // ----------------------------------------------------------------------------
591 void wxSockAddressImpl::CreateINET6()
593 wxASSERT_MSG( Is(FAMILY_UNSPEC
), "recreating address as different type?" );
595 m_family
= FAMILY_INET6
;
596 sockaddr_in6
* const addr
= ALLOC(sockaddr_in6
);
597 addr
->sin6_family
= FAMILY_INET6
;
600 bool wxSockAddressImpl::SetHostName6(const wxString
& hostname
)
602 sockaddr_in6
* const addr
= GET(sockaddr_in6
);
607 memset(&hints
, 0, sizeof(hints
));
608 hints
.ai_family
= AF_INET6
;
610 addrinfo
*info
= NULL
;
611 int rc
= getaddrinfo(hostname
.utf8_str(), NULL
, &hints
, &info
);
614 // use gai_strerror()?
618 wxCHECK_MSG( info
, false, "should have info on success" );
620 wxASSERT_MSG( int(info
->ai_addrlen
) == m_len
, "unexpected address length" );
622 memcpy(addr
, info
->ai_addr
, info
->ai_addrlen
);
628 bool wxSockAddressImpl::GetHostAddress(in6_addr
*address
) const
630 sockaddr_in6
* const addr
= GET(sockaddr_in6
);
634 *address
= addr
->sin6_addr
;
639 bool wxSockAddressImpl::SetHostAddress(const in6_addr
& address
)
641 sockaddr_in6
* const addr
= GET(sockaddr_in6
);
645 addr
->sin6_addr
= address
;
650 wxUint16
wxSockAddressImpl::GetPort6() const
652 sockaddr_in6
* const addr
= GET(sockaddr_in6
);
656 return ntohs(addr
->sin6_port
);
659 bool wxSockAddressImpl::SetPort6(wxUint16 port
)
661 sockaddr_in6
* const addr
= GET(sockaddr_in6
);
665 addr
->sin6_port
= htons(port
);
670 bool wxSockAddressImpl::SetToAnyAddress6()
672 static const in6_addr any
= IN6ADDR_ANY_INIT
;
674 return SetHostAddress(any
);
679 #ifdef wxHAS_UNIX_DOMAIN_SOCKETS
681 // ----------------------------------------------------------------------------
682 // Unix address family
683 // ----------------------------------------------------------------------------
685 #ifndef UNIX_PATH_MAX
686 #define UNIX_PATH_MAX (WXSIZEOF(((sockaddr_un *)NULL)->sun_path))
689 void wxSockAddressImpl::CreateUnix()
691 wxASSERT_MSG( Is(FAMILY_UNSPEC
), "recreating address as different type?" );
693 m_family
= FAMILY_UNIX
;
694 sockaddr_un
* const addr
= ALLOC(sockaddr_un
);
695 addr
->sun_family
= FAMILY_UNIX
;
696 addr
->sun_path
[0] = '\0';
699 bool wxSockAddressImpl::SetPath(const wxString
& path
)
701 sockaddr_un
* const addr
= GET(sockaddr_un
);
705 const wxScopedCharBuffer
buf(path
.utf8_str());
706 if ( strlen(buf
) >= UNIX_PATH_MAX
)
709 wxStrlcpy(addr
->sun_path
, buf
, UNIX_PATH_MAX
);
714 wxString
wxSockAddressImpl::GetPath() const
716 sockaddr_un
* const addr
= GET(sockaddr_un
);
720 return wxString::FromUTF8(addr
->sun_path
);
723 #endif // wxHAS_UNIX_DOMAIN_SOCKETS
728 // ----------------------------------------------------------------------------
730 // ----------------------------------------------------------------------------
732 const sockaddr
*wxSockAddress::GetAddressData() const
734 return GetAddress().GetAddr();
737 int wxSockAddress::GetAddressDataLen() const
739 return GetAddress().GetLen();
742 void wxSockAddress::Init()
744 if ( wxIsMainThread() && !wxSocketBase::IsInitialized() )
746 // we must do it before using any socket functions
747 (void)wxSocketBase::Initialize();
751 wxSockAddress::wxSockAddress()
755 m_impl
= new wxSockAddressImpl();
758 wxSockAddress::wxSockAddress(const wxSockAddress
& other
)
763 m_impl
= new wxSockAddressImpl(*other
.m_impl
);
766 wxSockAddress::~wxSockAddress()
771 void wxSockAddress::SetAddress(const wxSockAddressImpl
& address
)
773 if ( &address
!= m_impl
)
776 m_impl
= new wxSockAddressImpl(address
);
780 wxSockAddress
& wxSockAddress::operator=(const wxSockAddress
& addr
)
782 SetAddress(addr
.GetAddress());
787 void wxSockAddress::Clear()
792 // ----------------------------------------------------------------------------
794 // ----------------------------------------------------------------------------
796 wxSockAddressImpl
& wxIPaddress::GetImpl()
798 if ( m_impl
->GetFamily() == wxSockAddressImpl::FAMILY_UNSPEC
)
799 m_impl
->CreateINET();
804 bool wxIPaddress::Hostname(const wxString
& name
)
806 wxCHECK_MSG( !name
.empty(), false, "empty host name is invalid" );
808 m_origHostname
= name
;
810 return GetImpl().SetHostName(name
);
813 bool wxIPaddress::Service(const wxString
& name
)
815 return GetImpl().SetPortName(name
, "tcp");
818 bool wxIPaddress::Service(unsigned short port
)
820 return GetImpl().SetPort(port
);
823 bool wxIPaddress::LocalHost()
825 return Hostname("localhost");
828 wxString
wxIPaddress::Hostname() const
830 return GetImpl().GetHostName();
833 unsigned short wxIPaddress::Service() const
835 return GetImpl().GetPort();
838 bool wxIPaddress::operator==(const wxIPaddress
& addr
) const
840 return Hostname().Cmp(addr
.Hostname()) == 0 &&
841 Service() == addr
.Service();
844 bool wxIPaddress::AnyAddress()
846 return GetImpl().SetToAnyAddress();
849 // ----------------------------------------------------------------------------
851 // ----------------------------------------------------------------------------
853 void wxIPV4address::DoInitImpl()
855 m_impl
->CreateINET();
858 bool wxIPV4address::Hostname(unsigned long addr
)
860 if ( !GetImpl().SetHostAddress(addr
) )
862 m_origHostname
.clear();
866 m_origHostname
= Hostname();
870 bool wxIPV4address::IsLocalHost() const
872 return Hostname() == "localhost" || IPAddress() == "127.0.0.1";
875 wxString
wxIPV4address::IPAddress() const
878 if ( !GetImpl().GetHostAddress(&addr
) )
881 return wxString::Format
891 bool wxIPV4address::BroadcastAddress()
893 return GetImpl().SetToBroadcastAddress();
898 // ---------------------------------------------------------------------------
900 // ---------------------------------------------------------------------------
902 void wxIPV6address::DoInitImpl()
904 m_impl
->CreateINET6();
907 bool wxIPV6address::Hostname(unsigned char addr
[16])
909 unsigned short wk
[8];
910 for ( int i
= 0; i
< 8; ++i
)
914 wk
[i
] |= addr
[2*i
+1];
921 "%x:%x:%x:%x:%x:%x:%x:%x",
922 wk
[0], wk
[1], wk
[2], wk
[3], wk
[4], wk
[5], wk
[6], wk
[7]
927 bool wxIPV6address::IsLocalHost() const
929 if ( Hostname() == "localhost" )
932 wxString addr
= IPAddress();
933 return addr
== wxT("::1") ||
934 addr
== wxT("0:0:0:0:0:0:0:1") ||
935 addr
== wxT("::ffff:127.0.0.1");
938 wxString
wxIPV6address::IPAddress() const
946 if ( !GetImpl().GetHostAddress(&u
.addr6
) )
949 const wxUint8
* const addr
= u
.bytes
;
953 prefix_zero_count
= 0;
954 for ( i
= 0; i
< 8; ++i
)
956 words
[i
] = addr
[i
*2];
958 words
[i
] |= addr
[i
*2+1];
959 if ( i
== prefix_zero_count
&& words
[i
] == 0 )
964 if ( prefix_zero_count
== 8 )
966 result
= wxT( "::" );
968 else if ( prefix_zero_count
== 6 && words
[5] == 0xFFFF )
971 result
.Printf("::ffff:%d.%d.%d.%d",
972 addr
[12], addr
[13], addr
[14], addr
[15]);
977 for ( i
= prefix_zero_count
; i
< 8; ++i
)
979 result
+= wxString::Format(":%x", words
[i
]);
988 #ifdef wxHAS_UNIX_DOMAIN_SOCKETS
990 // ---------------------------------------------------------------------------
992 // ---------------------------------------------------------------------------
994 wxSockAddressImpl
& wxUNIXaddress::GetUNIX()
996 if ( m_impl
->GetFamily() == wxSockAddressImpl::FAMILY_UNSPEC
)
997 m_impl
->CreateUnix();
1002 void wxUNIXaddress::Filename(const wxString
& fname
)
1004 GetUNIX().SetPath(fname
);
1007 wxString
wxUNIXaddress::Filename() const
1009 return GetUNIX().GetPath();
1012 #endif // wxHAS_UNIX_DOMAIN_SOCKETS
1014 #endif // wxUSE_SOCKETS