aboutsummaryrefslogtreecommitdiff
path: root/gcc/ada/socket.c
diff options
context:
space:
mode:
authorDmitriy Anisimkov <anisimko@adacore.com>2018-12-11 11:12:32 +0000
committerPierre-Marie de Rodat <pmderodat@gcc.gnu.org>2018-12-11 11:12:32 +0000
commit759f1648029eef1fde1c66e342b033438c44e3b5 (patch)
treeab1a23e36f228d370e5baa848c6b474263994c34 /gcc/ada/socket.c
parentd71b0a9a041430612883f7f891bb25b8e21b6f2c (diff)
downloadgcc-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.c167
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) */