summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/Makefile.am3
-rw-r--r--lib/getaddrinfo.c312
-rw-r--r--lib/getaddrinfo.h67
-rw-r--r--lib/gethostbyname.c228
-rw-r--r--lib/gethostbyname.h103
5 files changed, 712 insertions, 1 deletions
diff --git a/lib/Makefile.am b/lib/Makefile.am
index d82f138..7826a28 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -2,9 +2,10 @@
2 2
3noinst_LIBRARIES = libnagiosplug.a 3noinst_LIBRARIES = libnagiosplug.a
4 4
5noinst_HEADERS = getopt.h 5noinst_HEADERS = getopt.h getaddrinfo.h gethostbyname.h
6 6
7libnagiosplug_a_SOURCES = getopt.c getopt1.c getloadavg.c 7libnagiosplug_a_SOURCES = getopt.c getopt1.c getloadavg.c
8 8
9INCLUDES = -I$(srcdir) 9INCLUDES = -I$(srcdir)
10 10
11EXTRA_DIST = getaddrinfo.c gethostbyname.c
diff --git a/lib/getaddrinfo.c b/lib/getaddrinfo.c
new file mode 100644
index 0000000..c958da6
--- /dev/null
+++ b/lib/getaddrinfo.c
@@ -0,0 +1,312 @@
1/*
2 * This file is part of libESMTP, a library for submission of RFC 2822
3 * formatted electronic mail messages using the SMTP protocol described
4 * in RFC 2821.
5 *
6 * Copyright (C) 2001,2002 Brian Stafford <brian@stafford.uklinux.net>
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 */
22
23/* An emulation of the RFC 2553 / Posix getaddrinfo resolver interface.
24 */
25
26#ifdef HAVE_CONFIG_H
27#include <config.h>
28#endif
29
30/* Need to turn off Posix features in glibc to build this */
31#undef _POSIX_C_SOURCE
32#undef _XOPEN_SOURCE
33
34#include <stdlib.h>
35#include <string.h>
36#include <ctype.h>
37#include <errno.h>
38
39#include <sys/socket.h>
40#include <netinet/in.h>
41#include <arpa/inet.h>
42
43#include <netdb.h>
44
45#include "gethostbyname.h"
46#include "getaddrinfo.h"
47
48static struct addrinfo *
49dup_addrinfo (struct addrinfo *info, void *addr, size_t addrlen)
50{
51 struct addrinfo *ret;
52
53 ret = malloc (sizeof (struct addrinfo));
54 if (ret == NULL)
55 return NULL;
56 memcpy (ret, info, sizeof (struct addrinfo));
57 ret->ai_addr = malloc (addrlen);
58 if (ret->ai_addr == NULL)
59 {
60 free (ret);
61 return NULL;
62 }
63 memcpy (ret->ai_addr, addr, addrlen);
64 ret->ai_addrlen = addrlen;
65 return ret;
66}
67
68int
69getaddrinfo (const char *nodename, const char *servname,
70 const struct addrinfo *hints, struct addrinfo **res)
71{
72 struct hostent *hp;
73 struct servent *servent;
74 const char *socktype;
75 int port;
76 struct addrinfo hint, result;
77 struct addrinfo *ai, *sai, *eai;
78 struct ghbnctx ghbnctx;
79 char **addrs;
80 int code;
81
82 memset (&result, 0, sizeof result);
83
84 /* default for hints */
85 if (hints == NULL)
86 {
87 memset (&hint, 0, sizeof hint);
88 hint.ai_family = PF_UNSPEC;
89 hints = &hint;
90 }
91
92 /* servname must not be NULL in this implementation */
93 if (servname == NULL)
94 return EAI_NONAME;
95
96 /* check for tcp or udp sockets only */
97 if (hints->ai_socktype == SOCK_STREAM)
98 socktype = "tcp";
99 else if (hints->ai_socktype == SOCK_DGRAM)
100 socktype = "udp";
101 else
102 return EAI_SERVICE;
103 result.ai_socktype = hints->ai_socktype;
104
105 /* Note: maintain port in host byte order to make debugging easier */
106 if (isdigit (*servname))
107 port = strtol (servname, NULL, 10);
108 else if ((servent = getservbyname (servname, socktype)) != NULL)
109 port = ntohs (servent->s_port);
110 else
111 return EAI_NONAME;
112
113 /* if nodename == NULL refer to the local host for a client or any
114 for a server */
115 if (nodename == NULL)
116 {
117 struct sockaddr_in sin;
118
119 /* check protocol family is PF_UNSPEC or PF_INET - could try harder
120 for IPv6 but that's more code than I'm prepared to write */
121 if (hints->ai_family == PF_UNSPEC || hints->ai_family == PF_INET)
122 result.ai_family = AF_INET;
123 else
124 return EAI_FAMILY;
125
126 sin.sin_family = result.ai_family;
127 sin.sin_port = htons (port);
128 if (hints->ai_flags & AI_PASSIVE)
129 sin.sin_addr.s_addr = htonl (INADDR_ANY);
130 else
131 sin.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
132 /* Duplicate result and addr and return */
133 *res = dup_addrinfo (&result, &sin, sizeof sin);
134 return (*res == NULL) ? EAI_MEMORY : 0;
135 }
136
137 /* If AI_NUMERIC is specified, use inet_addr to translate numbers and
138 dots notation. */
139 if (hints->ai_flags & AI_NUMERICHOST)
140 {
141 struct sockaddr_in sin;
142
143 /* check protocol family is PF_UNSPEC or PF_INET */
144 if (hints->ai_family == PF_UNSPEC || hints->ai_family == PF_INET)
145 result.ai_family = AF_INET;
146 else
147 return EAI_FAMILY;
148
149 sin.sin_family = result.ai_family;
150 sin.sin_port = htons (port);
151 sin.sin_addr.s_addr = inet_addr (nodename);
152 /* Duplicate result and addr and return */
153 *res = dup_addrinfo (&result, &sin, sizeof sin);
154 return (*res == NULL) ? EAI_MEMORY : 0;
155 }
156
157 errno = 0;
158 hp = gethostbyname_ctx (nodename, &ghbnctx);
159 if (hp == NULL)
160 {
161 if (errno != 0)
162 {
163 free_ghbnctx (&ghbnctx);
164 return EAI_SYSTEM;
165 }
166 code = h_error_ctx (&ghbnctx);
167 switch (code)
168 {
169 case HOST_NOT_FOUND: code = EAI_NODATA; break;
170 case NO_DATA: code = EAI_NODATA; break;
171#if defined(NO_ADDRESS) && NO_ADDRESS != NO_DATA
172 case NO_ADDRESS: code = EAI_NODATA; break;
173#endif
174 case NO_RECOVERY: code = EAI_FAIL; break;
175 case TRY_AGAIN: code = EAI_AGAIN; break;
176 default: code = EAI_FAIL; break;
177 }
178 free_ghbnctx (&ghbnctx);
179 return code;
180 }
181
182 /* Check that the address family is acceptable.
183 */
184 switch (hp->h_addrtype)
185 {
186 case AF_INET:
187 if (!(hints->ai_family == PF_UNSPEC || hints->ai_family == PF_INET))
188 goto eai_family;
189 break;
190#ifdef USE_IPV6
191 case AF_INET6:
192 if (!(hints->ai_family == PF_UNSPEC || hints->ai_family == PF_INET6))
193 goto eai_family;
194 break;
195#endif
196 default:
197 eai_family:
198 free_ghbnctx (&ghbnctx);
199 return EAI_FAMILY;
200 }
201
202 /* For each element pointed to by hp, create an element in the
203 result linked list. */
204 sai = eai = NULL;
205 for (addrs = hp->h_addr_list; *addrs != NULL; addrs++)
206 {
207 struct sockaddr sa;
208 size_t addrlen;
209
210 sa.sa_family = hp->h_addrtype;
211 switch (hp->h_addrtype)
212 {
213 case AF_INET:
214 ((struct sockaddr_in *) &sa)->sin_port = htons (port);
215 memcpy (&((struct sockaddr_in *) &sa)->sin_addr,
216 *addrs, hp->h_length);
217 addrlen = sizeof (struct sockaddr_in);
218 break;
219#ifdef USE_IPV6
220 case AF_INET6:
221# if SIN6_LEN
222 ((struct sockaddr_in6 *) &sa)->sin6_len = hp->h_length;
223# endif
224 ((struct sockaddr_in6 *) &sa)->sin6_port = htons (port);
225 memcpy (&((struct sockaddr_in6 *) &sa)->sin6_addr,
226 *addrs, hp->h_length);
227 addrlen = sizeof (struct sockaddr_in6);
228 break;
229#endif
230 default:
231 continue;
232 }
233
234 result.ai_family = hp->h_addrtype;
235 ai = dup_addrinfo (&result, &sa, addrlen);
236 if (ai == NULL)
237 {
238 free_ghbnctx (&ghbnctx);
239 freeaddrinfo (sai);
240 return EAI_MEMORY;
241 }
242 if (sai == NULL)
243 sai = ai;
244 else
245 eai->ai_next = ai;
246 eai = ai;
247 }
248
249 if (sai == NULL)
250 {
251 free_ghbnctx (&ghbnctx);
252 return EAI_NODATA;
253 }
254
255 if (hints->ai_flags & AI_CANONNAME)
256 {
257 sai->ai_canonname = malloc (strlen (hp->h_name) + 1);
258 if (sai->ai_canonname == NULL)
259 {
260 free_ghbnctx (&ghbnctx);
261 freeaddrinfo (sai);
262 return EAI_MEMORY;
263 }
264 strcpy (sai->ai_canonname, hp->h_name);
265 }
266
267 free_ghbnctx (&ghbnctx);
268 *res = sai;
269 return 0;
270}
271
272void
273freeaddrinfo (struct addrinfo *ai)
274{
275 struct addrinfo *next;
276
277 while (ai != NULL)
278 {
279 next = ai->ai_next;
280 if (ai->ai_canonname != NULL)
281 free (ai->ai_canonname);
282 if (ai->ai_addr != NULL)
283 free (ai->ai_addr);
284 free (ai);
285 ai = next;
286 }
287}
288
289const char *
290gai_strerror (int ecode)
291{
292 static const char *eai_descr[] =
293 {
294 "no error",
295 "address family for nodename not supported", /* EAI_ADDRFAMILY */
296 "temporary failure in name resolution", /* EAI_AGAIN */
297 "invalid value for ai_flags", /* EAI_BADFLAGS */
298 "non-recoverable failure in name resolution", /* EAI_FAIL */
299 "ai_family not supported", /* EAI_FAMILY */
300 "memory allocation failure", /* EAI_MEMORY */
301 "no address associated with nodename", /* EAI_NODATA */
302 "nodename nor servname provided, or not known", /* EAI_NONAME */
303 "servname not supported for ai_socktype", /* EAI_SERVICE */
304 "ai_socktype not supported", /* EAI_SOCKTYPE */
305 "system error returned in errno", /* EAI_SYSTEM */
306 };
307
308 if (ecode < 0 || ecode > (int) (sizeof eai_descr/ sizeof eai_descr[0]))
309 return "unknown error";
310 return eai_descr[ecode];
311}
312
diff --git a/lib/getaddrinfo.h b/lib/getaddrinfo.h
new file mode 100644
index 0000000..c474d3b
--- /dev/null
+++ b/lib/getaddrinfo.h
@@ -0,0 +1,67 @@
1#ifndef _getaddrinfo_h
2#define _getaddrinfo_h
3/*
4 * This file is part of libESMTP, a library for submission of RFC 2822
5 * formatted electronic mail messages using the SMTP protocol described
6 * in RFC 2821.
7 *
8 * Copyright (C) 2001,2002 Brian Stafford <brian@stafford.uklinux.net>
9 *
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
14 *
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
19 *
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 */
24
25/* Structure and prototypes aken from RFC 2553 */
26
27struct addrinfo
28 {
29 int ai_flags; /* AI_PASSIVE, AI_CANONNAME, AI_NUMERICHOST */
30 int ai_family; /* PF_xxx */
31 int ai_socktype; /* SOCK_xxx */
32 int ai_protocol; /* 0 or IPPROTO_xxx for IPv4 and IPv6 */
33 size_t ai_addrlen; /* length of ai_addr */
34 char *ai_canonname; /* canonical name for nodename */
35 struct sockaddr *ai_addr; /* binary address */
36 struct addrinfo *ai_next; /* next structure in linked list */
37 };
38
39/* Supposed to be defined in <netdb.h> */
40#define AI_PASSIVE 1 /* Socket address is intended for `bind'. */
41#define AI_CANONNAME 2 /* Request for canonical name. */
42#define AI_NUMERICHOST 4 /* Don't use name resolution. */
43
44/* Supposed to be defined in <netdb.h> */
45#define EAI_ADDRFAMILY 1 /* address family for nodename not supported */
46#define EAI_AGAIN 2 /* temporary failure in name resolution */
47#define EAI_BADFLAGS 3 /* invalid value for ai_flags */
48#define EAI_FAIL 4 /* non-recoverable failure in name resolution */
49#define EAI_FAMILY 5 /* ai_family not supported */
50#define EAI_MEMORY 6 /* memory allocation failure */
51#define EAI_NODATA 7 /* no address associated with nodename */
52#define EAI_NONAME 8 /* nodename nor servname provided, or not known */
53#define EAI_SERVICE 9 /* servname not supported for ai_socktype */
54#define EAI_SOCKTYPE 10 /* ai_socktype not supported */
55#define EAI_SYSTEM 11 /* system error returned in errno */
56
57/* RFC 2553 / Posix resolver */
58int getaddrinfo (const char *nodename, const char *servname,
59 const struct addrinfo *hints, struct addrinfo **res);
60
61/* Free addrinfo structure and associated storage */
62void freeaddrinfo (struct addrinfo *ai);
63
64/* Convert error return from getaddrinfo() to string */
65const char *gai_strerror (int code);
66
67#endif
diff --git a/lib/gethostbyname.c b/lib/gethostbyname.c
new file mode 100644
index 0000000..d151606
--- /dev/null
+++ b/lib/gethostbyname.c
@@ -0,0 +1,228 @@
1/*
2 * This file is a ghastly hack because nobody can agree on
3 * gethostbyname_r()'s prototype.
4 *
5 * Copyright (C) 2001,2002 Brian Stafford <brian@stafford.uklinux.net>
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */
21
22#ifdef HAVE_CONFIG_H
23#include <config.h>
24#endif
25
26#define _SVID_SOURCE 1 /* Need this to get gethostbyname_r() */
27
28#include <assert.h>
29
30#include <stdlib.h>
31#include <string.h>
32#include <netdb.h>
33#include <errno.h>
34
35#include "gethostbyname.h"
36
37#if HAVE_GETIPNODEBYNAME
38
39void
40free_ghbnctx (struct ghbnctx *ctx)
41{
42 assert (ctx != NULL);
43
44 if (ctx->hostent != NULL)
45 freehostent (ctx->hostent);
46}
47
48struct hostent *
49gethostbyname_ctx (const char *host, struct ghbnctx *ctx)
50{
51 assert (ctx != NULL);
52
53 memset (ctx, 0, sizeof (struct ghbnctx));
54 ctx->hostent = getipnodebyname (host, AF_UNSPEC, AI_ADDRCONFIG, &ctx->h_err);
55 return ctx->hostent;
56}
57
58int
59h_error_ctx (struct ghbnctx *ctx)
60{
61 assert (ctx != NULL);
62
63 return ctx->h_err;
64}
65
66#elif HAVE_GETHOSTBYNAME_R == 6
67
68void
69free_ghbnctx (struct ghbnctx *ctx)
70{
71 assert (ctx != NULL);
72
73 if (ctx->hostbuf != NULL)
74 free (ctx->hostbuf);
75}
76
77struct hostent *
78gethostbyname_ctx (const char *host, struct ghbnctx *ctx)
79{
80 struct hostent *hp;
81 char *tmp;
82 int err;
83
84 assert (ctx != NULL);
85
86 memset (ctx, 0, sizeof (struct ghbnctx));
87 ctx->hostbuf_len = 2048;
88 if ((ctx->hostbuf = malloc (ctx->hostbuf_len)) == NULL)
89 {
90 errno = ENOMEM;
91 return NULL;
92 }
93 while ((err = gethostbyname_r (host,
94 &ctx->hostent, ctx->hostbuf, ctx->hostbuf_len,
95 &hp, &ctx->h_err)) == ERANGE)
96 {
97 ctx->hostbuf_len += 1024;
98 if ((tmp = realloc (ctx->hostbuf, ctx->hostbuf_len)) == NULL)
99 {
100 errno = ENOMEM;
101 return NULL;
102 }
103 ctx->hostbuf = tmp;
104 }
105 if (err != 0)
106 {
107 errno = err;
108 return NULL;
109 }
110 return hp;
111}
112
113int
114h_error_ctx (struct ghbnctx *ctx)
115{
116 assert (ctx != NULL);
117
118 return ctx->h_err;
119}
120
121#elif HAVE_GETHOSTBYNAME_R == 5
122
123void
124free_ghbnctx (struct ghbnctx *ctx)
125{
126 assert (ctx != NULL);
127
128 if (ctx->hostbuf != NULL)
129 free (ctx->hostbuf);
130}
131
132struct hostent *
133gethostbyname_ctx (const char *host, struct ghbnctx *ctx)
134{
135 struct hostent *hp;
136 char *tmp;
137
138 assert (ctx != NULL);
139
140 memset (ctx, 0, sizeof (struct ghbnctx));
141 ctx->hostbuf_len = 2048;
142 if ((ctx->hostbuf = malloc (ctx->hostbuf_len)) == NULL)
143 {
144 errno = ENOMEM;
145 return NULL;
146 }
147 while ((hp = gethostbyname_r (host, &ctx->hostent,
148 ctx->hostbuf, ctx->hostbuf_len,
149 &ctx->h_err)) == NULL && errno == ERANGE)
150 {
151 ctx->hostbuf_len += 1024;
152 if ((tmp = realloc (ctx->hostbuf, ctx->hostbuf_len)) == NULL)
153 {
154 errno = ENOMEM;
155 return NULL;
156 }
157 ctx->hostbuf = tmp;
158 }
159 return hp;
160}
161
162int
163h_error_ctx (struct ghbnctx *ctx)
164{
165 assert (ctx != NULL);
166
167 return ctx->h_err;
168}
169
170#elif HAVE_GETHOSTBYNAME_R == 3
171
172void
173free_ghbnctx (struct ghbnctx *ctx)
174{
175 assert (ctx != NULL);
176
177 /* FIXME: does this need to do anything? */
178}
179
180struct hostent *
181gethostbyname_ctx (const char *host, struct ghbnctx *ctx)
182{
183 assert (ctx != NULL);
184
185 if (!gethostbyname_r (host, &ctx->hostent, &ctx->hostent_data))
186 {
187 ctx->h_err = h_errno; /* FIXME: is this correct? */
188 return NULL;
189 }
190 return &ctx->hostent;
191}
192
193int
194h_error_ctx (struct ghbnctx *ctx)
195{
196 assert (ctx != NULL);
197
198 return ctx->h_err;
199}
200
201#else
202
203void
204free_ghbnctx (struct ghbnctx *ctx __attribute__ ((unused)))
205{
206 assert (ctx != NULL);
207}
208
209struct hostent *
210gethostbyname_ctx (const char *host, struct ghbnctx *ctx)
211{
212 struct hostent *hp;
213
214 hp = gethostbyname (host);
215 if (hp == NULL)
216 ctx->h_err = h_errno;
217 return hp;
218}
219
220int
221h_error_ctx (struct ghbnctx *ctx)
222{
223 assert (ctx != NULL);
224
225 return ctx->h_err;
226}
227
228#endif
diff --git a/lib/gethostbyname.h b/lib/gethostbyname.h
new file mode 100644
index 0000000..2b96399
--- /dev/null
+++ b/lib/gethostbyname.h
@@ -0,0 +1,103 @@
1/*
2 * This file is a ghastly hack because nobody can agree on
3 * gethostbyname_r()'s prototype.
4 *
5 * Copyright (C) 2001,2002 Brian Stafford <brian@stafford.uklinux.net>
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */
21
22/*************************************************************************
23 Usage:
24
25 #include <errno.h>
26 #include "gethostbyname.h"
27
28 f ()
29 {
30 struct ghbnctx ctx;
31
32 errno = 0;
33 hp = gethostbyname_ctx (host, &ctx);
34 if (hp == NULL)
35 {
36 if (errno != 0)
37 handle_value_of_errno (errno);
38 else
39 handle_value_of_h_errno (h_error_ctx (&ctx));
40 }
41 else
42 {
43 ...
44 }
45 free_ghbnctx (&ctx);
46 }
47 *************************************************************************/
48
49#ifndef _gethostbyname_h
50#define _gethostbyname_h
51
52#if HAVE_GETIPNODEBYNAME
53
54struct ghbnctx
55 {
56 int h_err;
57 struct hostent *hostent;
58 };
59
60#elif HAVE_GETHOSTBYNAME_R == 6
61
62struct ghbnctx
63 {
64 int h_err;
65 struct hostent hostent;
66 char *hostbuf;
67 size_t hostbuf_len;
68 };
69
70#elif HAVE_GETHOSTBYNAME_R == 5
71
72struct ghbnctx
73 {
74 int h_err;
75 struct hostent hostent;
76 char *hostbuf;
77 int hostbuf_len;
78 };
79
80#elif HAVE_GETHOSTBYNAME_R == 3
81
82struct ghbnctx
83 {
84 int h_err;
85 struct hostent_data hostent_data;
86 struct hostent hostent;
87 };
88
89#else
90
91struct ghbnctx
92 {
93 int h_err;
94 };
95
96#endif
97
98struct hostent *gethostbyname_ctx (const char *host, struct ghbnctx *ctx);
99int h_error_ctx (struct ghbnctx *ctx);
100void free_ghbnctx (struct ghbnctx *ctx);
101
102#endif
103