diff options
author | Dmitriy Anisimkov <anisimko@adacore.com> | 2018-12-11 11:12:32 +0000 |
---|---|---|
committer | Pierre-Marie de Rodat <pmderodat@gcc.gnu.org> | 2018-12-11 11:12:32 +0000 |
commit | 759f1648029eef1fde1c66e342b033438c44e3b5 (patch) | |
tree | ab1a23e36f228d370e5baa848c6b474263994c34 /gcc/ada/socket.c | |
parent | d71b0a9a041430612883f7f891bb25b8e21b6f2c (diff) | |
download | gcc-759f1648029eef1fde1c66e342b033438c44e3b5.zip gcc-759f1648029eef1fde1c66e342b033438c44e3b5.tar.gz gcc-759f1648029eef1fde1c66e342b033438c44e3b5.tar.bz2 |
[Ada] GNAT.Sockets: add IPv6 support
2018-12-11 Dmitriy Anisimkov <anisimko@adacore.com>
gcc/ada/
* libgnat/g-socket.ads (Family_Type): Add new enumerated value
Family_Unspec to be able to use it in Get_Address_Info parameter
and find IPv4 together with IPv6 addresses.
(Inet_Addr_Bytes_Length): Zero length for Family_Unspec. New
IPv6 predefined constant addresses.
(IPv4_To_IPv6_Prefix): IPv4 mapped to IPv6 address prefix.
(Is_IPv4_Address): Rename from Is_IP_Address and published.
(Is_IPv6_Address): New routine.
(Image of Inet_Addr_Type): Fix description about IPv6 address
text representation.
(Level_Type): New propocol level IP_Protocol_For_IPv6_Level.
(Add_Membership_V4): New socket option equal to Add_Membership.
(Drop_Membership_V4): New socket option equal to
Drop_Membership.
(Multicast_If_V4): New socket option equal to Multicast_If.
(Multicast_Loop_V4, Add_Membership_V6, Drop_Membership_V6,
Multicast_If_V6, Multicast_Loop_V6, Multicast_Hops, IPv6_Only):
New socket option for IPv6.
(Address_Info): New record to keep address info.
(Address_Info_Array): Array to keep address info records.
(Get_Address_Info): Routine to get address info records by host
and service names.
(Host_Service): Record to keep host and service names.
(Get_Name_Info): New routine to get host and service names by
address.
(Create_Socket): Add Level parameter, IP_Protocol_For_IP_Level
default.
(Name_Array, Inet_Addr_Array): Change array index to Positive.
* libgnat/g-socket.adb (IPV6_Mreq): New record definition for
IPv6.
(Hex_To_Char): Remove.
(Short_To_Network, Network_To_Short): Move to package
GNAT.Sockets.Thin_Common.
(Is_IP_Address): Remove.
(To_In_Addr, To_Inet_Addr): Move to package
GNAT.Sockets.Thin_Common.
(Get_Socket_Option): Get value of Multicast_Loop option as
integer boolean, process IPv6 options. Don't try to get
Add_Membership_V4, Add_Membership_V6, Drop_Membership_V4, and
Drop_Membership_V6 as not supported by the socket API.
(Set_Socket_Option): Set value of Multicast_Loop option as
integer boolean, process IPv6 options.
* gsocket.h
(IPV6_ADD_MEMBERSHIP): Define from IPV6_JOIN_GROUP if necessary
for VxWorks.
(IPV6_DROP_MEMBERSHIP): Define from IPV6_LEAVE_GROUP if
necessary for VxWorks
(HAVE_INET_NTOP): New definition.
(HAVE_INET_PTON): Includes VxWorks now.
* socket.c (__gnat_getaddrinfo, __gnat_getnameinfo,
__gnat_freeaddrinfo, __gnat_gai_strerror, __gnat_inet_ntop): New
routines.
* libgnat/g-sothco.ads, libgnat/g-sothco.adb
(socklen_t, In6_Addr, To_In6_Addr): New.
(To_In_Addr, To_Inet_Addr): Move from package body GNAT.Sockets.
(To_Inet_Addr): New overload with In6_Addr type parmeter.
(In_Addr_Access_Array): Remove.
(Sockaddr): Unchecked_Union instead of Sockaddr_In and old
defined generic Sockaddr.
(Set_Address): Use it to set family, port and address into
Sockaddr.
(Get_Address): New routine to get Socket_Addr_Type from
Sockaddr.
(Addrinfo): Structure to use with getaddrinfo.
(C_Getaddrinfo, C_Freeaddrinfo, C_Getnameinfo, C_GAI_Strerror,
Inet_Ntop): New routine import.
(Short_To_Network, Network_To_Short): Move from package body
GNAT.Sockets.
* libgnat/g-stsifd__sockets.adb: Use Sockaddr instead of
Sockaddr_In.
* s-oscons-tmplt.c (AF_UNSPEC, EAI_SYSTEM, SOCK_RAW,
IPPROTO_IPV6, IP_RECVERR, SIZEOF_socklen_t, IF_NAMESIZE): New
constants.
(AI_xxxx_OFFSET): Constants to consider platform differences in
field positions and sizes for addrinfo structure.
(AI_xxxxx): Flags for getaddrinfo.
(NI_xxxxx): Flags for getnameinfo.
(IPV6_xxxxx): Socket options for IPv6.
(Inet_Ntop_Linkname): New routine.
From-SVN: r267016
Diffstat (limited to 'gcc/ada/socket.c')
-rw-r--r-- | gcc/ada/socket.c | 167 |
1 files changed, 160 insertions, 7 deletions
diff --git a/gcc/ada/socket.c b/gcc/ada/socket.c index ed5b8df..7f2b5ff 100644 --- a/gcc/ada/socket.c +++ b/gcc/ada/socket.c @@ -90,10 +90,27 @@ extern int __gnat_hostent_h_addrtype (struct hostent *); extern int __gnat_hostent_h_length (struct hostent *); extern char * __gnat_hostent_h_addr (struct hostent *, int); +extern int __gnat_getaddrinfo( + const char *node, + const char *service, + const struct addrinfo *hints, + struct addrinfo **res); +int __gnat_getnameinfo( + const struct sockaddr *sa, socklen_t salen, + char *host, size_t hostlen, + char *serv, size_t servlen, int flags); +extern void __gnat_freeaddrinfo(struct addrinfo *res); +extern const char * __gnat_gai_strerror(int errcode); + #ifndef HAVE_INET_PTON extern int __gnat_inet_pton (int, const char *, void *); #endif - + +#ifndef HAVE_INET_NTOP +extern const char * +__gnat_inet_ntop(int, const void *, char *, socklen_t); +#endif + /* Disable the sending of SIGPIPE for writes on a broken stream */ void @@ -112,7 +129,7 @@ __gnat_disable_all_sigpipes (void) (void) signal (SIGPIPE, SIG_IGN); #endif } - + #if defined (_WIN32) || defined (__vxworks) /* * Signalling FDs operations are implemented in Ada for these platforms @@ -128,7 +145,7 @@ int __gnat_create_signalling_fds (int *fds) { return pipe (fds); } - + /* * Read one byte of data from rsig, the read end of a pair of signalling fds * created by __gnat_create_signalling_fds. @@ -138,7 +155,7 @@ __gnat_read_signalling_fd (int rsig) { char c; return read (rsig, &c, 1); } - + /* * Write one byte of data to wsig, the write end of a pair of signalling fds * created by __gnat_create_signalling_fds. @@ -148,7 +165,7 @@ __gnat_write_signalling_fd (int wsig) { char c = 0; return write (wsig, &c, 1); } - + /* * Close one end of a pair of signalling fds */ @@ -157,7 +174,7 @@ __gnat_close_signalling_fd (int sig) { (void) close (sig); } #endif - + /* * Handling of gethostbyname, gethostbyaddr, getservbyname and getservbyport * ========================================================================= @@ -369,7 +386,7 @@ __gnat_getservbyport (int port, const char *proto, return 0; } #endif - + /* Find the largest socket in the socket set SET. This is needed for `select'. LAST is the maximum value for the largest socket. This hint is used to avoid scanning very large socket sets. On return, LAST is the @@ -572,6 +589,41 @@ __gnat_inet_pton (int af, const char *src, void *dst) { } #endif +#ifndef HAVE_INET_NTOP + +const char * +__gnat_inet_ntop(int af, const void *src, char *dst, socklen_t size) +{ +#ifdef _WIN32 + struct sockaddr_storage ss; + int sslen = sizeof ss; + memset(&ss, 0, sslen); + ss.ss_family = af; + + switch (af) { + case AF_INET6: + ((struct sockaddr_in6 *)&ss)->sin6_addr = *(struct in6_addr *)src; + break; + case AF_INET: + ((struct sockaddr_in *)&ss)->sin_addr = *(struct in_addr *)src; + break; + default: + errno = EAFNOSUPPORT; + return NULL; + } + + DWORD sz = size; + + if (WSAAddressToStringA((struct sockaddr*)&ss, sslen, 0, dst, &sz) != 0) { + return NULL; + } + return dst; +#else + return NULL; +#endif +} +#endif + /* * Accessor functions for struct hostent. */ @@ -650,4 +702,105 @@ __gnat_servent_s_proto (struct servent * s) return s->s_proto; } +#if defined(AF_INET6) && !defined(__rtems__) + +#if defined (__vxworks) +#define getaddrinfo ipcom_getaddrinfo +#define getnameinfo ipcom_getnameinfo +#define freeaddrinfo ipcom_freeaddrinfo +#endif + +int __gnat_getaddrinfo( + const char *node, + const char *service, + const struct addrinfo *hints, + struct addrinfo **res) +{ + return getaddrinfo(node, service, hints, res); +} + +int __gnat_getnameinfo( + const struct sockaddr *sa, socklen_t salen, + char *host, size_t hostlen, + char *serv, size_t servlen, int flags) +{ + return getnameinfo(sa, salen, host, hostlen, serv, servlen, flags); +} + +void __gnat_freeaddrinfo(struct addrinfo *res) { + freeaddrinfo(res); +} + +const char * __gnat_gai_strerror(int errcode) { +#if defined(_WIN32) || defined(__vxworks) + // gai_strerror thread usafe on Windows and is not available on some vxWorks + // versions + + switch (errcode) { + case EAI_AGAIN: + return "Temporary failure in name resolution."; + case EAI_BADFLAGS: + return "Invalid value for ai_flags."; + case EAI_FAIL: + return "Nonrecoverable failure in name resolution."; + case EAI_FAMILY: + return "The ai_family member is not supported."; + case EAI_MEMORY: + return "Memory allocation failure."; +#ifdef EAI_NODATA + // Could be not defined under the vxWorks + case EAI_NODATA: + return "No address associated with nodename."; +#endif +#if EAI_NODATA != EAI_NONAME + /* with mingw64 runtime EAI_NODATA and EAI_NONAME have the same value. + This applies to both win32 and win64 */ + case EAI_NONAME: + return "Neither nodename nor servname provided, or not known."; +#endif + case EAI_SERVICE: + return "The servname parameter is not supported for ai_socktype."; + case EAI_SOCKTYPE: + return "The ai_socktype member is not supported."; +#ifdef EAI_SYSTEM + // Could be not defined, at least on Windows + case EAI_SYSTEM: + return "System error returned in errno"; +#endif + default: + return "Unknown error."; + } +#else + return gai_strerror(errcode); +#endif +} + +#else + +int __gnat_getaddrinfo( + const char *node, + const char *service, + const struct addrinfo *hints, + struct addrinfo **res) +{ + return -1; +} + +int __gnat_getnameinfo( + const struct sockaddr *sa, socklen_t salen, + char *host, size_t hostlen, + char *serv, size_t servlen, int flags) +{ + return -1; +} + +void __gnat_freeaddrinfo(struct addrinfo *res) { +} + +const char * __gnat_gai_strerror(int errcode) { + return "getaddinfo functions family is not supported"; +} + +#endif + #endif /* defined(HAVE_SOCKETS) */ |