source: mainline/uspace/lib/inet/src/hostport.c@ d5ed54b

serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since d5ed54b was ec7902d, checked in by Jiri Svoboda <jiri@…>, 4 years ago

Move TCP/IP library support out of libc to separate library

  • Property mode set to 100644
File size: 7.0 KB
Line 
1/*
2 * Copyright (c) 2016 Jiri Svoboda
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup libc
30 * @{
31 */
32/** @file Internet host:port specification
33 *
34 * As in RFC 1738 Uniform Resouce Locators (URL) and RFC 2732 Format for
35 * literal IPv6 Addresses in URLs
36 */
37
38#include <assert.h>
39#include <errno.h>
40#include <inet/addr.h>
41#include <inet/dnsr.h>
42#include <inet/endpoint.h>
43#include <inet/hostname.h>
44#include <inet/hostport.h>
45#include <stdio.h>
46#include <stdlib.h>
47#include <str.h>
48
49/** Parse host:port string.
50 *
51 * @param str Host:port string
52 * @param rhp Place to store pointer to new hostport structure
53 * @param endptr Place to store pointer to next character in string or @c NULL
54 *
55 * @return EOK on success. EINVAL if @a str does not start with a valid
56 * host:port or if @a endptr is @c NULL and @a str contains
57 * extra characters at the end. ENOMEM if out of memory
58 */
59errno_t inet_hostport_parse(const char *str, inet_hostport_t **rhp,
60 char **endptr)
61{
62 inet_hostport_t *hp;
63 inet_addr_t addr;
64 uint16_t port;
65 char *name;
66 char *aend;
67 const char *pend;
68 errno_t rc;
69
70 hp = calloc(1, sizeof(inet_hostport_t));
71 if (hp == NULL)
72 return ENOMEM;
73
74 if (str[0] == '[') {
75 /* Try [<ip-addr-literal>] */
76 rc = inet_addr_parse(str + 1, &addr, &aend);
77 if (rc == EOK) {
78 if (*aend == ']') {
79 hp->hform = inet_host_addr;
80 hp->host.addr = addr;
81 ++aend;
82 }
83 goto have_host;
84 }
85 }
86
87 /* Try <ipv4-addr> */
88 rc = inet_addr_parse(str, &addr, &aend);
89 if (rc == EOK) {
90 hp->hform = inet_host_addr;
91 hp->host.addr = addr;
92 goto have_host;
93 }
94
95 /* Try <hostname> */
96 rc = inet_hostname_parse(str, &name, &aend);
97 if (rc == EOK) {
98 hp->hform = inet_host_name;
99 hp->host.name = name;
100 goto have_host;
101 }
102
103 free(hp);
104 return EINVAL;
105
106have_host:
107 if (*aend == ':') {
108 /* Port number */
109 rc = str_uint16_t(aend + 1, &pend, 10, false, &port);
110 if (rc != EOK) {
111 free(hp);
112 return EINVAL;
113 }
114 } else {
115 /* Port number omitted */
116 port = 0;
117 pend = aend;
118 }
119
120 hp->port = port;
121
122 if (*pend != '\0' && endptr == NULL) {
123 /* Extra characters */
124 free(hp);
125 return EINVAL;
126 }
127
128 *rhp = hp;
129 if (endptr != NULL)
130 *endptr = (char *)pend;
131 return EOK;
132}
133
134/** Convert host:port to string representation.
135 *
136 * @param hp Host:port structure
137 * @param rstr Place to store pointer to new string
138 * @return EOK on success, ENOMEM if out of memory
139 */
140errno_t inet_hostport_format(inet_hostport_t *hp, char **rstr)
141{
142 errno_t rc;
143 int ret;
144 char *astr, *str;
145 char *hstr = NULL;
146
147 switch (hp->hform) {
148 case inet_host_addr:
149 rc = inet_addr_format(&hp->host.addr, &astr);
150 if (rc != EOK) {
151 assert(rc == ENOMEM);
152 return ENOMEM;
153 }
154
155 if (hp->host.addr.version != ip_v4) {
156 hstr = astr;
157 } else {
158 ret = asprintf(&hstr, "[%s]", astr);
159 if (ret < 0) {
160 free(astr);
161 return ENOMEM;
162 }
163
164 free(astr);
165 }
166
167 break;
168 case inet_host_name:
169 hstr = str_dup(hp->host.name);
170 if (hstr == NULL)
171 return ENOMEM;
172 break;
173 }
174
175 ret = asprintf(&str, "%s:%u", hstr, hp->port);
176 if (ret < 0)
177 return ENOMEM;
178
179 free(hstr);
180 *rstr = str;
181 return EOK;
182}
183
184/** Destroy host:port structure.
185 *
186 * @param hp Host:port or @c NULL
187 */
188void inet_hostport_destroy(inet_hostport_t *hp)
189{
190 if (hp == NULL)
191 return;
192
193 switch (hp->hform) {
194 case inet_host_addr:
195 break;
196 case inet_host_name:
197 free(hp->host.name);
198 break;
199 }
200
201 free(hp);
202}
203
204/** Look up first endpoint corresponding to host:port.
205 *
206 * If host:port contains a host name, name resolution is performed.
207 *
208 * @param hp Host:port structure
209 * @param version Desired IP version (ip_any to get any version)
210 * @param ep Place to store endpoint
211 *
212 * @return EOK on success, ENOENT on resolution failure
213 */
214errno_t inet_hostport_lookup_one(inet_hostport_t *hp, ip_ver_t version,
215 inet_ep_t *ep)
216{
217 dnsr_hostinfo_t *hinfo = NULL;
218 errno_t rc;
219
220 inet_ep_init(ep);
221
222 switch (hp->hform) {
223 case inet_host_addr:
224 ep->addr = hp->host.addr;
225 break;
226 case inet_host_name:
227 rc = dnsr_name2host(hp->host.name, &hinfo, ip_any);
228 if (rc != EOK) {
229 dnsr_hostinfo_destroy(hinfo);
230 return ENOENT;
231 }
232
233 ep->addr = hinfo->addr;
234 dnsr_hostinfo_destroy(hinfo);
235 break;
236 }
237
238 ep->port = hp->port;
239 return EOK;
240}
241
242/** Look up first endpoint corresponding to host:port string.
243 *
244 * If host:port contains a host name, name resolution is performed.
245 *
246 * @param str Host:port string
247 * @param version Desired IP version (ip_any to get any version)
248 * @param ep Place to store endpoint
249 * @param endptr Place to store pointer to next character in string or @c NULL
250 * @param errmsg Place to store pointer to error message (no need to free it)
251 * or @c NULL
252 *
253 * @return EOK on success. EINVAL if @a str has incorrect format or if
254 * @a endptr is @c NULL and @a str contains extra characters at
255 * the end. ENOENT if host was not found during resolution,
256 * ENOMEM if out of memory
257 */
258errno_t inet_hostport_plookup_one(const char *str, ip_ver_t version, inet_ep_t *ep,
259 char **endptr, const char **errmsg)
260{
261 inet_hostport_t *hp = NULL;
262 char *eptr;
263 errno_t rc;
264
265 rc = inet_hostport_parse(str, &hp, endptr != NULL ? &eptr : NULL);
266 if (rc != EOK) {
267 switch (rc) {
268 case EINVAL:
269 if (errmsg != NULL)
270 *errmsg = "Invalid format";
271 goto error;
272 case ENOMEM:
273 if (errmsg != NULL)
274 *errmsg = "Out of memory";
275 goto error;
276 case EOK:
277 break;
278 default:
279 assert(false);
280 }
281 }
282
283 rc = inet_hostport_lookup_one(hp, version, ep);
284 if (rc != EOK) {
285 /* XXX Distinguish between 'not found' and other error */
286 rc = ENOENT;
287 if (errmsg != NULL)
288 *errmsg = "Name resolution failed";
289 goto error;
290 }
291
292 inet_hostport_destroy(hp);
293 if (endptr != NULL)
294 *endptr = eptr;
295 return EOK;
296error:
297 inet_hostport_destroy(hp);
298 return rc;
299}
300
301/** @}
302 */
Note: See TracBrowser for help on using the repository browser.