string: Use builtins for ffs and ffsll
[glibc.git] / inet / idna.c
blob453b5ea15882fdb804be42ebe2f9dd5e32d805d6
1 /* IDNA functions, forwarding to implementations in libidn2.
2 Copyright (C) 2018-2024 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>
24 #include <pointer_guard.h>
26 /* Use the soname and version to locate libidn2, to ensure a
27 compatible ABI. */
28 #define LIBIDN2_SONAME "libidn2.so.0"
29 #define LIBIDN2_VERSION "IDN2_0.0.0"
31 /* Return codes from libidn2. */
32 enum
34 IDN2_OK = 0,
35 IDN2_MALLOC = -100,
38 /* Functions from libidn2. */
39 struct functions
41 void *handle;
42 int (*lookup_ul) (const char *src, char **result, int flags);
43 int (*to_unicode_lzlz) (const char *name, char **result, int flags);
46 static void *
47 functions_allocate (void *closure)
49 struct functions *result = malloc (sizeof (*result));
50 if (result == NULL)
51 return NULL;
53 void *handle = __libc_dlopen (LIBIDN2_SONAME);
54 if (handle == NULL)
55 /* Do not cache open failures. The library may appear
56 later. */
58 free (result);
59 return NULL;
62 void *ptr_lookup_ul
63 = __libc_dlvsym (handle, "idn2_lookup_ul", LIBIDN2_VERSION);
64 void *ptr_to_unicode_lzlz
65 = __libc_dlvsym (handle, "idn2_to_unicode_lzlz", LIBIDN2_VERSION);
66 if (ptr_lookup_ul == NULL || ptr_to_unicode_lzlz == NULL)
68 __libc_dlclose (handle);
69 free (result);
70 return NULL;
73 result->handle = handle;
74 result->lookup_ul = ptr_lookup_ul;
75 result->to_unicode_lzlz = ptr_to_unicode_lzlz;
76 PTR_MANGLE (result->lookup_ul);
77 PTR_MANGLE (result->to_unicode_lzlz);
79 return result;
82 static void
83 functions_deallocate (void *closure, void *ptr)
85 struct functions *functions = ptr;
86 __libc_dlclose (functions->handle);
87 free (functions);
90 /* Ensure that *functions is initialized and return the value of the
91 pointer. If the library cannot be loaded, return NULL. */
92 static inline struct functions *
93 get_functions (void)
95 static void *functions;
96 return allocate_once (&functions, functions_allocate, functions_deallocate,
97 NULL);
100 /* strdup with an EAI_* error code. */
101 static int
102 gai_strdup (const char *name, char **result)
104 char *ptr = __strdup (name);
105 if (ptr == NULL)
106 return EAI_MEMORY;
107 *result = ptr;
108 return 0;
112 __idna_to_dns_encoding (const char *name, char **result)
114 switch (__idna_name_classify (name))
116 case idna_name_ascii:
117 /* Nothing to convert. */
118 return gai_strdup (name, result);
119 case idna_name_nonascii:
120 /* Encoding needed. Handled below. */
121 break;
122 case idna_name_nonascii_backslash:
123 case idna_name_encoding_error:
124 return EAI_IDN_ENCODE;
125 case idna_name_memory_error:
126 return EAI_MEMORY;
127 case idna_name_error:
128 return EAI_SYSTEM;
131 struct functions *functions = get_functions ();
132 if (functions == NULL)
133 /* We report this as an encoding error (assuming that libidn2 is
134 not installed), although the root cause may be a temporary
135 error condition due to resource shortage. */
136 return EAI_IDN_ENCODE;
137 char *ptr = NULL;
138 __typeof__ (functions->lookup_ul) fptr = functions->lookup_ul;
139 PTR_DEMANGLE (fptr);
140 int ret = fptr (name, &ptr, 0);
141 if (ret == 0)
143 /* Assume that idn2_free is equivalent to free. */
144 *result = ptr;
145 return 0;
147 else if (ret == IDN2_MALLOC)
148 return EAI_MEMORY;
149 else
150 return EAI_IDN_ENCODE;
152 libc_hidden_def (__idna_to_dns_encoding)
155 __idna_from_dns_encoding (const char *name, char **result)
157 struct functions *functions = get_functions ();
158 if (functions == NULL)
159 /* Simply use the encoded name, assuming that it is not punycode
160 (but even a punycode name would be syntactically valid). */
161 return gai_strdup (name, result);
162 char *ptr = NULL;
163 __typeof__ (functions->to_unicode_lzlz) fptr = functions->to_unicode_lzlz;
164 PTR_DEMANGLE (fptr);
165 int ret = fptr (name, &ptr, 0);
166 if (ret == 0)
168 /* Assume that idn2_free is equivalent to free. */
169 *result = ptr;
170 return 0;
172 else if (ret == IDN2_MALLOC)
173 return EAI_MEMORY;
174 else
175 return EAI_IDN_ENCODE;
177 libc_hidden_def (__idna_from_dns_encoding)