]>
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"
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"
53 #include <arpa/inet.h>
57 #define INADDR_NONE INADDR_ANY
60 // ----------------------------------------------------------------------------
62 // ----------------------------------------------------------------------------
64 IMPLEMENT_ABSTRACT_CLASS(wxSockAddress
, wxObject
)
65 IMPLEMENT_ABSTRACT_CLASS(wxIPaddress
, wxSockAddress
)
66 IMPLEMENT_DYNAMIC_CLASS(wxIPV4address
, wxIPaddress
)
68 IMPLEMENT_DYNAMIC_CLASS(wxIPV6address
, wxIPaddress
)
70 #if defined(__UNIX__) && !defined(__WINDOWS__) && !defined(__WINE__)
71 IMPLEMENT_DYNAMIC_CLASS(wxUNIXaddress
, wxSockAddress
)
74 // ============================================================================
75 // implementation of thread-safe/reentrant functions if they're missing
76 // ============================================================================
78 // TODO: use POSIX getaddrinfo() (also available in Winsock 2) for simplicity
79 // and to use the same code for IPv4 and IPv6 support
82 #define HAVE_INET_ADDR
84 #define HAVE_GETHOSTBYNAME
85 #define HAVE_GETSERVBYNAME
87 // under MSW getxxxbyname() functions are MT-safe (but not reentrant) so
88 // we don't need to serialize calls to them
89 #define wxHAS_MT_SAFE_GETBY_FUNCS
92 // this header does dynamic dispatching of getaddrinfo/freeaddrinfo()
93 // by implementing them in its own code if the system versions are not
94 // available (as is the case for anything < XP)
96 // NB: if this is not available for the other compilers (so far tested
97 // with MSVC only) we should just use wxDynamicLibrary "manually"
99 // disable a warning occurring in Microsoft own version of this file
100 #pragma warning(disable:4706)
104 #pragma warning(default:4706)
109 // we assume that we have gethostbyaddr_r() if and only if we have
110 // gethostbyname_r() and that it uses the similar conventions to it (see
111 // comment in configure)
112 #define HAVE_GETHOSTBYADDR HAVE_GETHOSTBYNAME
113 #ifdef HAVE_FUNC_GETHOSTBYNAME_R_3
114 #define HAVE_FUNC_GETHOSTBYADDR_R_3
116 #ifdef HAVE_FUNC_GETHOSTBYNAME_R_5
117 #define HAVE_FUNC_GETHOSTBYADDR_R_5
119 #ifdef HAVE_FUNC_GETHOSTBYNAME_R_6
120 #define HAVE_FUNC_GETHOSTBYADDR_R_6
123 // the _r functions need the extra buffer parameter but unfortunately its type
124 // differs between different systems and for the systems which use opaque
125 // structs for it (at least AIX and OpenBSD) it must be zero-filled before
126 // being passed to the system functions
127 #ifdef HAVE_FUNC_GETHOSTBYNAME_R_3
128 struct wxGethostBuf
: hostent_data
132 memset(this, 0, sizeof(hostent_data
));
136 typedef char wxGethostBuf
[1024];
139 #ifdef HAVE_FUNC_GETSERVBYNAME_R_3
140 struct wxGetservBuf
: servent_data
144 memset(this, 0, sizeof(servent_data
));
148 typedef char wxGetservBuf
[1024];
151 #ifdef wxHAS_MT_SAFE_GETBY_FUNCS
152 #define wxLOCK_GETBY_MUTEX(name)
153 #else // may need mutexes to protect getxxxbyxxx() calls
154 #if defined(HAVE_GETHOSTBYNAME) || \
155 defined(HAVE_GETHOSTBYADDR) || \
156 defined(HAVE_GETSERVBYNAME)
157 #include "wx/thread.h"
161 // these mutexes are used to serialize
162 wxMutex nameLock
, // gethostbyname()
163 addrLock
, // gethostbyaddr()
164 servLock
; // getservbyname()
167 #define wxLOCK_GETBY_MUTEX(name) wxMutexLocker locker(name ## Lock)
168 #endif // we don't have _r functions
169 #endif // wxUSE_THREADS
174 #if defined(HAVE_GETHOSTBYNAME)
175 hostent
*deepCopyHostent(hostent
*h
,
181 /* copy old structure */
182 memcpy(h
, he
, sizeof(hostent
));
185 int len
= strlen(h
->h_name
);
191 memcpy(buffer
, h
->h_name
, len
);
195 /* track position in the buffer */
198 /* reuse len to store address length */
201 /* ensure pointer alignment */
202 unsigned int misalign
= sizeof(char *) - pos%sizeof
(char *);
203 if(misalign
< sizeof(char *))
206 /* leave space for pointer list */
207 char **p
= h
->h_addr_list
, **q
;
208 char **h_addr_list
= (char **)(buffer
+ pos
);
210 pos
+= sizeof(char *);
212 /* copy addresses and fill new pointer list */
213 for (p
= h
->h_addr_list
, q
= h_addr_list
; *p
!= 0; p
++, q
++)
215 if (size
< pos
+ len
)
220 memcpy(buffer
+ pos
, *p
, len
); /* copy content */
221 *q
= buffer
+ pos
; /* set copied pointer to copied content */
224 *++q
= 0; /* null terminate the pointer list */
225 h
->h_addr_list
= h_addr_list
; /* copy pointer to pointers */
227 /* ensure word alignment of pointers */
228 misalign
= sizeof(char *) - pos%sizeof
(char *);
229 if(misalign
< sizeof(char *))
232 /* leave space for pointer list */
234 char **h_aliases
= (char **)(buffer
+ pos
);
236 pos
+= sizeof(char *);
238 /* copy aliases and fill new pointer list */
239 for (p
= h
->h_aliases
, q
= h_aliases
; *p
!= 0; p
++, q
++)
242 if (size
<= pos
+ len
)
247 memcpy(buffer
+ pos
, *p
, len
); /* copy content */
248 buffer
[pos
+ len
] = '\0';
249 *q
= buffer
+ pos
; /* set copied pointer to copied content */
252 *++q
= 0; /* null terminate the pointer list */
253 h
->h_aliases
= h_aliases
; /* copy pointer to pointers */
257 #endif // HAVE_GETHOSTBYNAME
259 hostent
*wxGethostbyname_r(const char *hostname
,
266 #if defined(HAVE_FUNC_GETHOSTBYNAME_R_6)
267 gethostbyname_r(hostname
, h
, buffer
, size
, &he
, err
);
268 #elif defined(HAVE_FUNC_GETHOSTBYNAME_R_5)
269 he
= gethostbyname_r(hostname
, h
, buffer
, size
, err
);
270 #elif defined(HAVE_FUNC_GETHOSTBYNAME_R_3)
271 he
= gethostbyname_r(hostname
, h
, &buffer
);
273 #elif defined(HAVE_GETHOSTBYNAME)
274 wxLOCK_GETBY_MUTEX(name
);
276 he
= gethostbyname(hostname
);
280 he
= deepCopyHostent(h
, he
, buffer
, size
, err
);
282 #error "No gethostbyname[_r]()"
288 hostent
*wxGethostbyaddr_r(const char *addr_buf
,
297 #if defined(HAVE_FUNC_GETHOSTBYADDR_R_6)
298 gethostbyaddr_r(addr_buf
, buf_size
, proto
, h
, buffer
, size
, &he
, err
);
299 #elif defined(HAVE_FUNC_GETHOSTBYADDR_R_5)
300 he
= gethostbyaddr_r(addr_buf
, buf_size
, proto
, h
, buffer
, size
, err
);
301 #elif defined(HAVE_FUNC_GETHOSTBYADDR_R_3)
302 he
= gethostbyaddr_r(addr_buf
, buf_size
, proto
, h
, buffer
);
304 #elif defined(HAVE_GETHOSTBYADDR)
305 wxLOCK_GETBY_MUTEX(addr
);
307 he
= gethostbyaddr(addr_buf
, buf_size
, proto
);
311 he
= deepCopyHostent(h
, he
, buffer
, size
, err
);
313 #error "No gethostbyaddr[_r]()"
319 #if defined(HAVE_GETSERVBYNAME)
320 servent
*deepCopyServent(servent
*s
,
325 /* copy plain old structure */
326 memcpy(s
, se
, sizeof(servent
));
329 int len
= strlen(s
->s_name
);
334 memcpy(buffer
, s
->s_name
, len
);
338 /* track position in the buffer */
342 len
= strlen(s
->s_proto
);
343 if (pos
+ len
>= size
)
347 memcpy(buffer
+ pos
, s
->s_proto
, len
);
348 buffer
[pos
+ len
] = '\0';
349 s
->s_proto
= buffer
+ pos
;
351 /* track position in the buffer */
354 /* ensure pointer alignment */
355 unsigned int misalign
= sizeof(char *) - pos%sizeof
(char *);
356 if(misalign
< sizeof(char *))
359 /* leave space for pointer list */
360 char **p
= s
->s_aliases
, **q
;
361 char **s_aliases
= (char **)(buffer
+ pos
);
363 pos
+= sizeof(char *);
365 /* copy addresses and fill new pointer list */
366 for (p
= s
->s_aliases
, q
= s_aliases
; *p
!= 0; p
++, q
++){
368 if (size
<= pos
+ len
)
372 memcpy(buffer
+ pos
, *p
, len
); /* copy content */
373 buffer
[pos
+ len
] = '\0';
374 *q
= buffer
+ pos
; /* set copied pointer to copied content */
377 *++q
= 0; /* null terminate the pointer list */
378 s
->s_aliases
= s_aliases
; /* copy pointer to pointers */
381 #endif // HAVE_GETSERVBYNAME
383 servent
*wxGetservbyname_r(const char *port
,
384 const char *protocol
,
390 #if defined(HAVE_FUNC_GETSERVBYNAME_R_6)
391 getservbyname_r(port
, protocol
, serv
, buffer
, size
, &se
);
392 #elif defined(HAVE_FUNC_GETSERVBYNAME_R_5)
393 se
= getservbyname_r(port
, protocol
, serv
, buffer
, size
);
394 #elif defined(HAVE_FUNC_GETSERVBYNAME_R_4)
395 se
= getservbyname_r(port
, protocol
, serv
, &buffer
);
396 #elif defined(HAVE_GETSERVBYNAME)
397 wxLOCK_GETBY_MUTEX(serv
);
399 se
= getservbyname(port
, protocol
);
401 se
= deepCopyServent(serv
, se
, buffer
, size
);
403 #error "No getservbyname[_r]()"
408 } // anonymous namespace
410 // ============================================================================
411 // wxSockAddressImpl implementation
412 // ============================================================================
414 // FIXME-VC6: helper macros to call Alloc/Get() hiding the ugly dummy argument
415 #define ALLOC(T) Alloc(static_cast<T *>(NULL))
416 #define GET(T) Get(static_cast<T *>(NULL))
418 // ----------------------------------------------------------------------------
419 // INET or INET6 address family
420 // ----------------------------------------------------------------------------
422 wxString
wxSockAddressImpl::GetHostName() const
428 if ( m_family
== FAMILY_INET6
)
430 sockaddr_in6
* const addr6
= GET(sockaddr_in6
);
431 addrbuf
= &addr6
->sin6_addr
;
432 addrbuflen
= sizeof(addr6
->sin6_addr
);
437 sockaddr_in
* const addr
= GET(sockaddr_in
);
441 addrbuf
= &addr
->sin_addr
;
442 addrbuflen
= sizeof(addr
->sin_addr
);
448 if ( !wxGethostbyaddr_r
450 static_cast<const char *>(addrbuf
),
462 return wxString::FromUTF8(he
.h_name
);
465 bool wxSockAddressImpl::SetPortName(const wxString
& name
, const char *protocol
)
467 // test whether it's a number first
469 if ( name
.ToULong(&port
) )
474 else // it's a service name
478 if ( !wxGetservbyname_r(name
.utf8_str(), protocol
, &se
,
479 buffer
, sizeof(buffer
)) )
482 // s_port is in network byte order and SetPort() uses the host byte
483 // order and we prefer to reuse it from here instead of assigning to
485 port
= ntohs(se
.s_port
);
488 return SetPort(port
);
491 // ----------------------------------------------------------------------------
492 // INET address family
493 // ----------------------------------------------------------------------------
495 void wxSockAddressImpl::CreateINET()
497 wxASSERT_MSG( Is(FAMILY_UNSPEC
), "recreating address as different type?" );
499 m_family
= FAMILY_INET
;
500 sockaddr_in
* const addr
= ALLOC(sockaddr_in
);
501 addr
->sin_family
= FAMILY_INET
;
504 bool wxSockAddressImpl::SetHostName4(const wxString
& name
)
506 sockaddr_in
* const addr
= GET(sockaddr_in
);
510 const wxUTF8Buf
namebuf(name
.utf8_str());
512 // first check if this is an address in quad dotted notation
513 #if defined(HAVE_INET_ATON)
514 if ( inet_aton(namebuf
, &addr
->sin_addr
) )
516 #elif defined(HAVE_INET_ADDR)
517 addr
->sin_addr
.s_addr
= inet_addr(namebuf
);
518 if ( addr
->sin_addr
.s_addr
!= INADDR_NONE
)
521 #error "Neither inet_aton() nor inet_addr() is available?"
524 // it's a host name, resolve it
528 if ( !wxGethostbyname_r(namebuf
, &he
, buffer
, sizeof(buffer
), &err
) )
531 addr
->sin_addr
.s_addr
= ((in_addr
*)he
.h_addr
)->s_addr
;
535 bool wxSockAddressImpl::GetHostAddress(wxUint32
*address
) const
537 sockaddr_in
* const addr
= GET(sockaddr_in
);
541 *address
= ntohl(addr
->sin_addr
.s_addr
);
546 bool wxSockAddressImpl::SetHostAddress(wxUint32 address
)
548 sockaddr_in
* const addr
= GET(sockaddr_in
);
552 addr
->sin_addr
.s_addr
= htonl(address
);
557 wxUint16
wxSockAddressImpl::GetPort4() const
559 sockaddr_in
* const addr
= GET(sockaddr_in
);
563 return ntohs(addr
->sin_port
);
566 bool wxSockAddressImpl::SetPort4(wxUint16 port
)
568 sockaddr_in
* const addr
= GET(sockaddr_in
);
572 addr
->sin_port
= htons(port
);
579 // ----------------------------------------------------------------------------
580 // INET6 address family
581 // ----------------------------------------------------------------------------
583 void wxSockAddressImpl::CreateINET6()
585 wxASSERT_MSG( Is(FAMILY_UNSPEC
), "recreating address as different type?" );
587 m_family
= FAMILY_INET6
;
588 sockaddr_in6
* const addr
= ALLOC(sockaddr_in6
);
589 addr
->sin6_family
= FAMILY_INET6
;
592 bool wxSockAddressImpl::SetHostName6(const wxString
& hostname
)
594 sockaddr_in6
* const addr
= GET(sockaddr_in6
);
599 memset(&hints
, 0, sizeof(hints
));
600 hints
.ai_family
= AF_INET6
;
602 addrinfo
*info
= NULL
;
603 int rc
= getaddrinfo(hostname
.utf8_str(), NULL
, &hints
, &info
);
606 // use gai_strerror()?
610 wxCHECK_MSG( info
, false, "should have info on success" );
612 wxASSERT_MSG( int(info
->ai_addrlen
) == m_len
, "unexpected address length" );
614 memcpy(addr
, info
->ai_addr
, info
->ai_addrlen
);
620 bool wxSockAddressImpl::GetHostAddress(in6_addr
*address
) const
622 sockaddr_in6
* const addr
= GET(sockaddr_in6
);
626 *address
= addr
->sin6_addr
;
631 bool wxSockAddressImpl::SetHostAddress(const in6_addr
& address
)
633 sockaddr_in6
* const addr
= GET(sockaddr_in6
);
637 addr
->sin6_addr
= address
;
642 wxUint16
wxSockAddressImpl::GetPort6() const
644 sockaddr_in6
* const addr
= GET(sockaddr_in6
);
648 return ntohs(addr
->sin6_port
);
651 bool wxSockAddressImpl::SetPort6(wxUint16 port
)
653 sockaddr_in6
* const addr
= GET(sockaddr_in6
);
657 addr
->sin6_port
= htons(port
);
662 bool wxSockAddressImpl::SetToAnyAddress6()
664 static const in6_addr any
= IN6ADDR_ANY_INIT
;
666 return SetHostAddress(any
);
671 #ifdef wxHAS_UNIX_DOMAIN_SOCKETS
673 // ----------------------------------------------------------------------------
674 // Unix address family
675 // ----------------------------------------------------------------------------
677 #ifndef UNIX_PATH_MAX
678 #define UNIX_PATH_MAX (WXSIZEOF(((sockaddr_un *)NULL)->sun_path))
681 void wxSockAddressImpl::CreateUnix()
683 wxASSERT_MSG( Is(FAMILY_UNSPEC
), "recreating address as different type?" );
685 m_family
= FAMILY_UNIX
;
686 sockaddr_un
* const addr
= ALLOC(sockaddr_un
);
687 addr
->sun_family
= FAMILY_UNIX
;
688 addr
->sun_path
[0] = '\0';
691 bool wxSockAddressImpl::SetPath(const wxString
& path
)
693 sockaddr_un
* const addr
= GET(sockaddr_un
);
697 const wxUTF8Buf
buf(path
.utf8_str());
698 if ( strlen(buf
) >= UNIX_PATH_MAX
)
701 wxStrlcpy(addr
->sun_path
, buf
, UNIX_PATH_MAX
);
706 wxString
wxSockAddressImpl::GetPath() const
708 sockaddr_un
* const addr
= GET(sockaddr_un
);
712 return wxString::FromUTF8(addr
->sun_path
);
715 #endif // wxHAS_UNIX_DOMAIN_SOCKETS
720 // ----------------------------------------------------------------------------
722 // ----------------------------------------------------------------------------
724 void wxSockAddress::Init()
726 if ( !wxSocketBase::IsInitialized() )
728 // we must do it before using any socket functions
729 (void)wxSocketBase::Initialize();
733 wxSockAddress::wxSockAddress()
737 m_impl
= new wxSockAddressImpl();
740 wxSockAddress::wxSockAddress(const wxSockAddress
& other
)
745 m_impl
= new wxSockAddressImpl(*other
.m_impl
);
748 wxSockAddress::~wxSockAddress()
753 void wxSockAddress::SetAddress(const wxSockAddressImpl
& address
)
755 if ( &address
!= m_impl
)
758 m_impl
= new wxSockAddressImpl(address
);
762 wxSockAddress
& wxSockAddress::operator=(const wxSockAddress
& addr
)
764 SetAddress(addr
.GetAddress());
769 void wxSockAddress::Clear()
774 // ----------------------------------------------------------------------------
776 // ----------------------------------------------------------------------------
778 wxSockAddressImpl
& wxIPaddress::GetImpl()
780 if ( m_impl
->GetFamily() == wxSockAddressImpl::FAMILY_UNSPEC
)
781 m_impl
->CreateINET();
786 bool wxIPaddress::Hostname(const wxString
& name
)
788 wxCHECK_MSG( !name
.empty(), false, "empty host name is invalid" );
790 m_origHostname
= name
;
792 return GetImpl().SetHostName(name
);
795 bool wxIPaddress::Service(const wxString
& name
)
797 return GetImpl().SetPortName(name
, "tcp");
800 bool wxIPaddress::Service(unsigned short port
)
802 return GetImpl().SetPort(port
);
805 bool wxIPaddress::LocalHost()
807 return Hostname("localhost");
810 wxString
wxIPaddress::Hostname() const
812 return GetImpl().GetHostName();
815 unsigned short wxIPaddress::Service() const
817 return GetImpl().GetPort();
820 bool wxIPaddress::operator==(const wxIPaddress
& addr
) const
822 return Hostname().Cmp(addr
.Hostname()) == 0 &&
823 Service() == addr
.Service();
826 bool wxIPaddress::AnyAddress()
828 return GetImpl().SetToAnyAddress();
831 // ----------------------------------------------------------------------------
833 // ----------------------------------------------------------------------------
835 void wxIPV4address::DoInitImpl()
837 m_impl
->CreateINET();
840 bool wxIPV4address::Hostname(unsigned long addr
)
842 if ( !GetImpl().SetHostAddress(addr
) )
844 m_origHostname
.clear();
848 m_origHostname
= Hostname();
852 bool wxIPV4address::IsLocalHost() const
854 return Hostname() == "localhost" || IPAddress() == "127.0.0.1";
857 wxString
wxIPV4address::IPAddress() const
860 if ( !GetImpl().GetHostAddress(&addr
) )
863 return wxString::Format
873 bool wxIPV4address::BroadcastAddress()
875 return GetImpl().SetToBroadcastAddress();
880 // ---------------------------------------------------------------------------
882 // ---------------------------------------------------------------------------
884 void wxIPV6address::DoInitImpl()
886 m_impl
->CreateINET6();
889 bool wxIPV6address::Hostname(unsigned char addr
[16])
891 unsigned short wk
[8];
892 for ( int i
= 0; i
< 8; ++i
)
896 wk
[i
] |= addr
[2*i
+1];
903 "%x:%x:%x:%x:%x:%x:%x:%x",
904 wk
[0], wk
[1], wk
[2], wk
[3], wk
[4], wk
[5], wk
[6], wk
[7]
909 bool wxIPV6address::IsLocalHost() const
911 if ( Hostname() == "localhost" )
914 wxString addr
= IPAddress();
915 return addr
== wxT("::1") ||
916 addr
== wxT("0:0:0:0:0:0:0:1") ||
917 addr
== wxT("::ffff:127.0.0.1");
920 wxString
wxIPV6address::IPAddress() const
928 if ( !GetImpl().GetHostAddress(&u
.addr6
) )
931 const wxUint8
* const addr
= u
.bytes
;
935 prefix_zero_count
= 0;
936 for ( i
= 0; i
< 8; ++i
)
938 words
[i
] = addr
[i
*2];
940 words
[i
] |= addr
[i
*2+1];
941 if ( i
== prefix_zero_count
&& words
[i
] == 0 )
946 if ( prefix_zero_count
== 8 )
948 result
= wxT( "::" );
950 else if ( prefix_zero_count
== 6 && words
[5] == 0xFFFF )
953 result
.Printf("::ffff:%d.%d.%d.%d",
954 addr
[12], addr
[13], addr
[14], addr
[15]);
959 for ( i
= prefix_zero_count
; i
< 8; ++i
)
961 result
+= wxString::Format(":%x", words
[i
]);
970 #ifdef wxHAS_UNIX_DOMAIN_SOCKETS
972 // ---------------------------------------------------------------------------
974 // ---------------------------------------------------------------------------
976 wxSockAddressImpl
& wxUNIXaddress::GetUNIX()
978 if ( m_impl
->GetFamily() == wxSockAddressImpl::FAMILY_UNSPEC
)
979 m_impl
->CreateUnix();
984 void wxUNIXaddress::Filename(const wxString
& fname
)
986 GetUNIX().SetPath(fname
);
989 wxString
wxUNIXaddress::Filename() const
991 return GetUNIX().GetPath();
994 #endif // wxHAS_UNIX_DOMAIN_SOCKETS
996 #endif // wxUSE_SOCKETS