1 | /* idn-stub.c --- Stub to dlopen libcidn.so and invoke idna_to_ascii_lz. |
2 | * Copyright (C) 2003, 2004 Simon Josefsson |
3 | * |
4 | * This file is part of GNU Libidn. |
5 | * |
6 | * GNU Libidn is free software; you can redistribute it and/or |
7 | * modify it under the terms of the GNU Lesser General Public |
8 | * License as published by the Free Software Foundation; either |
9 | * version 2.1 of the License, or (at your option) any later version. |
10 | * |
11 | * GNU Libidn is distributed in the hope that it will be useful, |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
14 | * Lesser General Public License for more details. |
15 | * |
16 | * You should have received a copy of the GNU Lesser General Public |
17 | * License along with GNU Libidn; if not, see <http://www.gnu.org/licenses/>. |
18 | */ |
19 | |
20 | #include <ctype.h> |
21 | #include <stdio.h> |
22 | #include <string.h> |
23 | #include <dlfcn.h> |
24 | #include <gnu/lib-names.h> |
25 | #include <libc-lock.h> |
26 | |
27 | /* Get specification for idna_to_ascii_lz. */ |
28 | #include "idna.h" |
29 | |
30 | /* Handle of the libidn DSO. */ |
31 | static void *h; |
32 | |
33 | |
34 | static int (*to_ascii_lz) (const char *input, char **output, int flags); |
35 | static int (*to_unicode_lzlz) (const char *input, char **output, int flags); |
36 | |
37 | |
38 | static void |
39 | load_dso (void) |
40 | { |
41 | /* Lock protecting the DSO loading. */ |
42 | __libc_lock_define_initialized (static, lock); |
43 | |
44 | __libc_lock_lock (lock); |
45 | |
46 | /* Retest in case some other thread arrived here at the same time. */ |
47 | if (h == NULL) |
48 | { |
49 | h = __libc_dlopen (LIBCIDN_SO); |
50 | |
51 | if (h == NULL) |
52 | h = (void *) 1l; |
53 | else |
54 | { |
55 | /* Get the function we are interested in. */ |
56 | to_ascii_lz = __libc_dlsym (h, "idna_to_ascii_lz" ); |
57 | to_unicode_lzlz = __libc_dlsym (h, "idna_to_unicode_lzlz" ); |
58 | if (to_ascii_lz == NULL || to_unicode_lzlz == NULL) |
59 | { |
60 | __libc_dlclose (h); |
61 | h = (void *) 1l; |
62 | } |
63 | } |
64 | } |
65 | |
66 | __libc_lock_unlock (lock); |
67 | } |
68 | |
69 | |
70 | /* Stub to dlopen libcidn.so and invoke the real idna_to_ascii_lz, or |
71 | return IDNA_DLOPEN_ERROR on failure. */ |
72 | int |
73 | __idna_to_unicode_lzlz (const char *input, char **output, int flags) |
74 | { |
75 | /* If the input string contains no "xn--" prefix for a component of |
76 | the name we can pass it up right away. */ |
77 | const char *cp = input; |
78 | while (*cp != '\0') |
79 | { |
80 | if (strncmp (cp, IDNA_ACE_PREFIX, strlen (IDNA_ACE_PREFIX)) == 0) |
81 | break; |
82 | |
83 | /* On to the next part of the name. */ |
84 | cp = __strchrnul (cp, '.'); |
85 | if (*cp == '.') |
86 | ++cp; |
87 | } |
88 | |
89 | if (*cp == '\0') |
90 | { |
91 | *output = (char *) input; |
92 | return IDNA_SUCCESS; |
93 | } |
94 | |
95 | if (h == NULL) |
96 | load_dso (); |
97 | |
98 | if (h == (void *) 1l) |
99 | return IDNA_DLOPEN_ERROR; |
100 | |
101 | return to_unicode_lzlz (input, output, flags); |
102 | } |
103 | |
104 | |
105 | /* Stub to dlopen libcidn.so and invoke the real idna_to_ascii_lz, or |
106 | return IDNA_DLOPEN_ERROR on failure. */ |
107 | int |
108 | __idna_to_ascii_lz (const char *input, char **output, int flags) |
109 | { |
110 | /* If the input string contains no non-ASCII character the output |
111 | string will be the same. No valid locale encoding does not have |
112 | this property. */ |
113 | const char *cp = input; |
114 | while (*cp != '\0' && isascii (*cp)) |
115 | ++cp; |
116 | |
117 | if (*cp == '\0') |
118 | { |
119 | *output = (char *) input; |
120 | return IDNA_SUCCESS; |
121 | } |
122 | |
123 | if (h == NULL) |
124 | load_dso (); |
125 | |
126 | if (h == (void *) 1l) |
127 | return IDNA_DLOPEN_ERROR; |
128 | |
129 | return to_ascii_lz (input, output, flags); |
130 | } |
131 | |
132 | |
133 | #if IS_IN (libc) |
134 | libc_freeres_fn (unload_libidn) |
135 | { |
136 | if (h != NULL && h != (void *) 1l) |
137 | { |
138 | __libc_dlclose (h); |
139 | h = (void *) 1l; |
140 | } |
141 | } |
142 | #endif |
143 | |