Changeset fab2746 in mainline for uspace/lib/c/generic/inet/addr.c
- Timestamp:
- 2015-04-08T21:25:30Z (10 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- 99ea91b2
- Parents:
- ba0eac5
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/lib/c/generic/inet/addr.c
rba0eac5 rfab2746 36 36 #include <errno.h> 37 37 #include <unistd.h> 38 #include <net/socket_codes.h>39 38 #include <inet/addr.h> 40 #include <net/inet.h>41 39 #include <stdio.h> 42 40 #include <malloc.h> … … 44 42 45 43 #define INET_PREFIXSTRSIZE 5 44 45 #define INET6_ADDRSTRLEN (8 * 4 + 7 + 1) 46 46 47 47 #if !(defined(__BE__) ^ defined(__LE__)) … … 178 178 naddr->addr6[15] = h & 0xff; 179 179 naddr->prefix = prefix; 180 }181 182 /** Determine address version.183 *184 * @param text Address in common notation.185 * @param af Place to store address version.186 *187 * @return EOK on success, EINVAL if input is not in valid format.188 *189 */190 static int inet_addr_version(const char *text, ip_ver_t *ver)191 {192 char *dot = str_chr(text, '.');193 if (dot != NULL) {194 *ver = ip_v4;195 return EOK;196 }197 198 char *collon = str_chr(text, ':');199 if (collon != NULL) {200 *ver = ip_v6;201 return EOK;202 }203 204 return EINVAL;205 }206 207 static int ipver_af(ip_ver_t ver)208 {209 switch (ver) {210 case ip_any:211 return AF_NONE;212 case ip_v4:213 return AF_INET;214 case ip_v6:215 return AF_INET6;216 default:217 assert(false);218 return EINVAL;219 }220 }221 222 ip_ver_t ipver_from_af(int af)223 {224 switch (af) {225 case AF_NONE:226 return ip_any;227 case AF_INET:228 return ip_v4;229 case AF_INET6:230 return ip_v6;231 default:232 assert(false);233 return EINVAL;234 }235 180 } 236 181 … … 343 288 } 344 289 290 static int inet_addr_parse_v4(const char *str, inet_addr_t *raddr, 291 int *prefix) 292 { 293 uint32_t a = 0; 294 uint8_t b; 295 char *cur = (char *)str; 296 size_t i = 0; 297 298 while (i < 4) { 299 int rc = str_uint8_t(cur, (const char **)&cur, 10, false, &b); 300 if (rc != EOK) 301 return rc; 302 303 a = (a << 8) + b; 304 305 i++; 306 307 if (*cur == 0) 308 break; 309 310 if (*cur != '.') 311 return EINVAL; 312 313 if (i < 4) 314 cur++; 315 } 316 317 if (prefix != NULL) { 318 *prefix = strtoul(cur, &cur, 10); 319 if (*prefix > 32) 320 return EINVAL; 321 } 322 323 if (i != 4 || (*cur != 0)) 324 return EINVAL; 325 326 raddr->version = ip_v4; 327 raddr->addr = a; 328 329 return EOK; 330 } 331 332 static int inet_addr_parse_v6(const char *str, inet_addr_t *raddr, int *prefix) 333 { 334 /* XXX */ 335 return EINVAL; 336 } 337 345 338 /** Parse node address. 346 339 * … … 353 346 int inet_addr_parse(const char *text, inet_addr_t *addr) 354 347 { 355 int rc = inet_addr_version(text, &addr->version); 356 if (rc != EOK) 357 return rc; 358 359 uint8_t buf[16]; 360 rc = inet_pton(ipver_af(addr->version), text, buf); 361 if (rc != EOK) 362 return rc; 363 364 switch (addr->version) { 365 case ip_v4: 366 addr->addr = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | 367 buf[3]; 368 break; 369 case ip_v6: 370 memcpy(addr->addr6, buf, 16); 371 break; 372 default: 373 return EINVAL; 374 } 375 376 return EOK; 348 int rc; 349 350 rc = inet_addr_parse_v4(text, addr, NULL); 351 if (rc == EOK) 352 return EOK; 353 354 rc = inet_addr_parse_v6(text, addr, NULL); 355 if (rc == EOK) 356 return EOK; 357 358 return EINVAL; 377 359 } 378 360 … … 387 369 int inet_naddr_parse(const char *text, inet_naddr_t *naddr) 388 370 { 389 char *slash = str_chr(text, '/'); 390 if (slash == NULL) 391 return EINVAL; 392 393 *slash = 0; 394 395 int rc = inet_addr_version(text, &naddr->version); 396 if (rc != EOK) 397 return rc; 398 399 uint8_t buf[16]; 400 rc = inet_pton(ipver_af(naddr->version), text, buf); 401 *slash = '/'; 402 403 if (rc != EOK) 404 return rc; 405 406 slash++; 407 uint8_t prefix; 408 409 switch (naddr->version) { 410 case ip_v4: 411 prefix = strtoul(slash, &slash, 10); 412 if (prefix > 32) 371 int rc; 372 inet_addr_t addr; 373 int prefix; 374 375 rc = inet_addr_parse_v4(text, &addr, &prefix); 376 if (rc == EOK) { 377 inet_addr_naddr(&addr, prefix, naddr); 378 return EOK; 379 } 380 381 rc = inet_addr_parse_v6(text, &addr, &prefix); 382 if (rc == EOK) { 383 inet_addr_naddr(&addr, prefix, naddr); 384 return EOK; 385 } 386 387 return EINVAL; 388 } 389 390 static int inet_ntop6(const uint8_t *data, char *address, size_t length) 391 { 392 /* Check output buffer size */ 393 if (length < INET6_ADDRSTRLEN) 394 return ENOMEM; 395 396 /* Find the longest zero subsequence */ 397 398 uint16_t zeroes[8]; 399 uint16_t bioctets[8]; 400 401 for (size_t i = 8; i > 0; i--) { 402 size_t j = i - 1; 403 404 bioctets[j] = (data[j << 1] << 8) | data[(j << 1) + 1]; 405 406 if (bioctets[j] == 0) { 407 zeroes[j] = 1; 408 if (j < 7) 409 zeroes[j] += zeroes[j + 1]; 410 } else 411 zeroes[j] = 0; 412 } 413 414 size_t wildcard_pos = (size_t) -1; 415 size_t wildcard_size = 0; 416 417 for (size_t i = 0; i < 8; i++) { 418 if (zeroes[i] > wildcard_size) { 419 wildcard_pos = i; 420 wildcard_size = zeroes[i]; 421 } 422 } 423 424 char *cur = address; 425 size_t rest = length; 426 bool tail_zero = false; 427 int ret; 428 429 for (size_t i = 0; i < 8; i++) { 430 if ((i == wildcard_pos) && (wildcard_size > 1)) { 431 ret = snprintf(cur, rest, ":"); 432 i += wildcard_size - 1; 433 tail_zero = true; 434 } else if (i == 0) { 435 ret = snprintf(cur, rest, "%" PRIx16, bioctets[i]); 436 tail_zero = false; 437 } else { 438 ret = snprintf(cur, rest, ":%" PRIx16, bioctets[i]); 439 tail_zero = false; 440 } 441 442 if (ret < 0) 413 443 return EINVAL; 414 444 415 naddr->addr = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | 416 buf[3]; 417 naddr->prefix = prefix; 418 419 break; 420 case ip_v6: 421 prefix = strtoul(slash, &slash, 10); 422 if (prefix > 128) 445 cur += ret; 446 rest -= ret; 447 } 448 449 if (tail_zero) { 450 ret = snprintf(cur, rest, ":"); 451 if (ret < 0) 423 452 return EINVAL; 424 425 memcpy(naddr->addr6, buf, 16);426 naddr->prefix = prefix;427 428 break;429 default:430 return ENOTSUP;431 453 } 432 454 433 455 return EOK; 434 456 } 457 435 458 436 459 /** Format node address. … … 462 485 return ENOMEM; 463 486 464 return inet_ntop (AF_INET6,addr->addr6, *bufp, INET6_ADDRSTRLEN);487 return inet_ntop6(addr->addr6, *bufp, INET6_ADDRSTRLEN); 465 488 default: 489 asprintf(bufp, "<ver=%d>", addr->version); 466 490 return ENOTSUP; 467 491 } … … 503 527 return ENOMEM; 504 528 505 rc = inet_ntop (AF_INET6,naddr->addr6, *bufp,529 rc = inet_ntop6(naddr->addr6, *bufp, 506 530 INET6_ADDRSTRLEN + INET_PREFIXSTRSIZE); 507 531 if (rc != EOK) { … … 586 610 } 587 611 588 void inet_sockaddr_in_addr(const sockaddr_in_t *sockaddr_in, inet_addr_t *addr)589 {590 addr->version = ip_v4;591 addr->addr = uint32_t_be2host(sockaddr_in->sin_addr.s_addr);592 }593 594 612 void inet_addr_set6(addr128_t v6, inet_addr_t *addr) 595 613 { … … 605 623 } 606 624 607 void inet_sockaddr_in6_addr(const sockaddr_in6_t *sockaddr_in6,608 inet_addr_t *addr)609 {610 addr->version = ip_v6;611 addr128_t_be2host(sockaddr_in6->sin6_addr.s6_addr, addr->addr6);612 }613 614 uint16_t inet_addr_sockaddr_in(const inet_addr_t *addr,615 sockaddr_in_t *sockaddr_in, sockaddr_in6_t *sockaddr_in6)616 {617 switch (addr->version) {618 case ip_v4:619 if (sockaddr_in != NULL) {620 sockaddr_in->sin_family = AF_INET;621 sockaddr_in->sin_addr.s_addr = host2uint32_t_be(addr->addr);622 }623 break;624 case ip_v6:625 if (sockaddr_in6 != NULL) {626 sockaddr_in6->sin6_family = AF_INET6;627 host2addr128_t_be(addr->addr6, sockaddr_in6->sin6_addr.s6_addr);628 }629 break;630 default:631 assert(false);632 break;633 }634 635 return ipver_af(addr->version);636 }637 638 int inet_addr_sockaddr(const inet_addr_t *addr, uint16_t port,639 sockaddr_t **nsockaddr, socklen_t *naddrlen)640 {641 sockaddr_in_t *sa4;642 sockaddr_in6_t *sa6;643 644 switch (addr->version) {645 case ip_v4:646 sa4 = calloc(1, sizeof(sockaddr_in_t));647 if (sa4 == NULL)648 return ENOMEM;649 650 sa4->sin_family = AF_INET;651 sa4->sin_port = host2uint16_t_be(port);652 sa4->sin_addr.s_addr = host2uint32_t_be(addr->addr);653 if (nsockaddr != NULL)654 *nsockaddr = (sockaddr_t *)sa4;655 if (naddrlen != NULL)656 *naddrlen = sizeof(*sa4);657 break;658 case ip_v6:659 sa6 = calloc(1, sizeof(sockaddr_in6_t));660 if (sa6 == NULL)661 return ENOMEM;662 663 sa6->sin6_family = AF_INET6;664 sa6->sin6_port = host2uint16_t_be(port);665 host2addr128_t_be(addr->addr6, sa6->sin6_addr.s6_addr);666 if (nsockaddr != NULL)667 *nsockaddr = (sockaddr_t *)sa6;668 if (naddrlen != NULL)669 *naddrlen = sizeof(*sa6);670 break;671 default:672 assert(false);673 break;674 }675 676 return EOK;677 }678 679 625 /** @} 680 626 */
Note:
See TracChangeset
for help on using the changeset viewer.