Add mnw language code [BZ #25139]
[glibc.git] / inet / idna.c
blob63680927bfda976094baf9b32c5326e4fcb991b3
1 /* IDNA functions, forwarding to implementations in libidn2.
2 Copyright (C) 2018-2019 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, see
17 <https://www.gnu.org/licenses/>. */
19 #include <allocate_once.h>
20 #include <dlfcn.h>
21 #include <inet/net-internal.h>
22 #include <netdb.h>
23 #include <stdbool.h>
25 /* Use the soname and version to locate libidn2, to ensure a
26 compatible ABI. */
27 #define LIBIDN2_SONAME "libidn2.so.0"
28 #define LIBIDN2_VERSION "IDN2_0.0.0"
30 /* Return codes from libidn2. */
31 enum
33 IDN2_OK = 0,
34 IDN2_MALLOC = -100,
37 /* Functions from libidn2. */
38 struct functions
40 void *handle;
41 int (*lookup_ul) (const char *src, char **result, int flags);
42 int (*to_unicode_lzlz) (const char *name, char **result, int flags);
45 static void *
46 functions_allocate (void *closure)
48 struct functions *result = malloc (sizeof (*result));
49 if (result == NULL)
50 return NULL;
52 void *handle = __libc_dlopen (LIBIDN2_SONAME);
53 if (handle == NULL)
54 /* Do not cache open failures. The library may appear
55 later. */
57 free (result);
58 return NULL;
61 void *ptr_lookup_ul
62 = __libc_dlvsym (handle, "idn2_lookup_ul", LIBIDN2_VERSION);
63 void *ptr_to_unicode_lzlz
64 = __libc_dlvsym (handle, "idn2_to_unicode_lzlz", LIBIDN2_VERSION);
65 if (ptr_lookup_ul == NULL || ptr_to_unicode_lzlz == NULL)
67 __libc_dlclose (handle);
68 free (result);
69 return NULL;
72 result->handle = handle;
73 result->lookup_ul = ptr_lookup_ul;
74 result->to_unicode_lzlz = ptr_to_unicode_lzlz;
75 #ifdef PTR_MANGLE
76 PTR_MANGLE (result->lookup_ul);
77 PTR_MANGLE (result->to_unicode_lzlz);
78 #endif
80 return result;
83 static void
84 functions_deallocate (void *closure, void *ptr)
86 struct functions *functions = ptr;
87 __libc_dlclose (functions->handle);
88 free (functions);
91 /* Ensure that *functions is initialized and return the value of the
92 pointer. If the library cannot be loaded, return NULL. */
93 static inline struct functions *
94 get_functions (void)
96 static void *functions;
97 return allocate_once (&functions, functions_allocate, functions_deallocate,
98 NULL);
101 /* strdup with an EAI_* error code. */
102 static int
103 gai_strdup (const char *name, char **result)
105 char *ptr = __strdup (name);
106 if (ptr == NULL)
107 return EAI_MEMORY;
108 *result = ptr;
109 return 0;
113 __idna_to_dns_encoding (const char *name, char **result)
115 switch (__idna_name_classify (name))
117 case idna_name_ascii:
118 /* Nothing to convert. */
119 return gai_strdup (name, result);
120 case idna_name_nonascii:
121 /* Encoding needed. Handled below. */
122 break;
123 case idna_name_nonascii_backslash:
124 case idna_name_encoding_error:
125 return EAI_IDN_ENCODE;
126 case idna_name_memory_error:
127 return EAI_MEMORY;
128 case idna_name_error:
129 return EAI_SYSTEM;
132 struct functions *functions = get_functions ();
133 if (functions == NULL)
134 /* We report this as an encoding error (assuming that libidn2 is
135 not installed), although the root cause may be a temporary
136 error condition due to resource shortage. */
137 return EAI_IDN_ENCODE;
138 char *ptr = NULL;
139 __typeof__ (functions->lookup_ul) fptr = functions->lookup_ul;
140 #ifdef PTR_DEMANGLE
141 PTR_DEMANGLE (fptr);
142 #endif
143 int ret = fptr (name, &ptr, 0);
144 if (ret == 0)
146 /* Assume that idn2_free is equivalent to free. */
147 *result = ptr;
148 return 0;
150 else if (ret == IDN2_MALLOC)
151 return EAI_MEMORY;
152 else
153 return EAI_IDN_ENCODE;
155 libc_hidden_def (__idna_to_dns_encoding)
158 __idna_from_dns_encoding (const char *name, char **result)
160 struct functions *functions = get_functions ();
161 if (functions == NULL)
162 /* Simply use the encoded name, assuming that it is not punycode
163 (but even a punycode name would be syntactically valid). */
164 return gai_strdup (name, result);
165 char *ptr = NULL;
166 __typeof__ (functions->to_unicode_lzlz) fptr = functions->to_unicode_lzlz;
167 #ifdef PTR_DEMANGLE
168 PTR_DEMANGLE (fptr);
169 #endif
170 int ret = fptr (name, &ptr, 0);
171 if (ret == 0)
173 /* Assume that idn2_free is equivalent to free. */
174 *result = ptr;
175 return 0;
177 else if (ret == IDN2_MALLOC)
178 return EAI_MEMORY;
179 else
180 return EAI_IDN_ENCODE;
182 libc_hidden_def (__idna_from_dns_encoding)