Changeset fb4d788 in mainline for uspace/lib/c/generic/inet/addr.c
- Timestamp:
- 2015-07-28T11:28:14Z (9 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- 6accc5cf
- Parents:
- df2bce3 (diff), 47726b5e (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the(diff)
links above to see all the changes relative to each parent. - File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/lib/c/generic/inet/addr.c
rdf2bce3 rfb4d788 1 1 /* 2 2 * Copyright (c) 2013 Jiri Svoboda 3 * Copyright (c) 2013 Martin Decky 3 4 * All rights reserved. 4 5 * … … 36 37 #include <errno.h> 37 38 #include <unistd.h> 38 #include <net/socket_codes.h>39 39 #include <inet/addr.h> 40 #include <net/inet.h>41 40 #include <stdio.h> 42 41 #include <malloc.h> … … 44 43 45 44 #define INET_PREFIXSTRSIZE 5 45 46 #define INET6_ADDRSTRLEN (8 * 4 + 7 + 1) 46 47 47 48 #if !(defined(__BE__) ^ defined(__LE__)) … … 180 181 } 181 182 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 }236 237 183 void inet_naddr_addr(const inet_naddr_t *naddr, inet_addr_t *addr) 238 184 { … … 288 234 if (naddr->version != addr->version) 289 235 return 0; 290 236 291 237 switch (naddr->version) { 292 238 case ip_v4: … … 315 261 if (naddr->prefix > 128) 316 262 return 0; 317 263 318 264 size_t pos = 0; 319 265 for (size_t i = 0; i < 16; i++) { … … 321 267 if (naddr->prefix < pos) 322 268 break; 323 269 324 270 if (naddr->prefix - pos > 8) { 325 271 /* Comparison without masking */ … … 333 279 return 0; 334 280 } 335 281 336 282 pos += 8; 337 283 } 338 284 339 285 return 1; 340 286 default: … … 343 289 } 344 290 291 static int inet_addr_parse_v4(const char *str, inet_addr_t *raddr, 292 int *prefix) 293 { 294 uint32_t a = 0; 295 uint8_t b; 296 char *cur = (char *)str; 297 size_t i = 0; 298 299 while (i < 4) { 300 int rc = str_uint8_t(cur, (const char **)&cur, 10, false, &b); 301 if (rc != EOK) 302 return rc; 303 304 a = (a << 8) + b; 305 306 i++; 307 308 if (*cur == '\0' || *cur == '/') 309 break; 310 311 if (*cur != '.') 312 return EINVAL; 313 314 if (i < 4) 315 cur++; 316 } 317 318 if (prefix != NULL) { 319 if (*cur != '/') 320 return EINVAL; 321 cur++; 322 323 *prefix = strtoul(cur, &cur, 10); 324 if (*prefix > 32) 325 return EINVAL; 326 } 327 328 if (i != 4 || (*cur != '\0')) 329 return EINVAL; 330 331 raddr->version = ip_v4; 332 raddr->addr = a; 333 334 return EOK; 335 } 336 337 static int inet_addr_parse_v6(const char *str, inet_addr_t *raddr, int *prefix) 338 { 339 uint8_t data[16]; 340 341 memset(data, 0, 16); 342 343 const char *cur = str; 344 size_t i = 0; 345 size_t wildcard_pos = (size_t) -1; 346 size_t wildcard_size = 0; 347 348 /* Handle initial wildcard */ 349 if ((str[0] == ':') && (str[1] == ':')) { 350 cur = str + 2; 351 wildcard_pos = 0; 352 wildcard_size = 16; 353 354 /* Handle the unspecified address */ 355 if (*cur == '\0') 356 goto success; 357 } 358 359 while (i < 16) { 360 uint16_t bioctet; 361 int rc = str_uint16_t(cur, &cur, 16, false, &bioctet); 362 if (rc != EOK) 363 return rc; 364 365 data[i] = (bioctet >> 8) & 0xff; 366 data[i + 1] = bioctet & 0xff; 367 368 if (wildcard_pos != (size_t) -1) { 369 if (wildcard_size < 2) 370 return EINVAL; 371 372 wildcard_size -= 2; 373 } 374 375 i += 2; 376 377 if (*cur != ':') 378 break; 379 380 if (i < 16) { 381 cur++; 382 383 /* Handle wildcard */ 384 if (*cur == ':') { 385 if (wildcard_pos != (size_t) -1) 386 return EINVAL; 387 388 wildcard_pos = i; 389 wildcard_size = 16 - i; 390 cur++; 391 392 if (*cur == '\0' || *cur == '/') 393 break; 394 } 395 } 396 } 397 398 if (prefix != NULL) { 399 if (*cur != '/') 400 return EINVAL; 401 cur++; 402 403 *prefix = strtoul(cur, (char **)&cur, 10); 404 if (*prefix > 128) 405 return EINVAL; 406 } 407 408 if (*cur != '\0') 409 return EINVAL; 410 411 /* Create wildcard positions */ 412 if ((wildcard_pos != (size_t) -1) && (wildcard_size > 0)) { 413 size_t wildcard_shift = 16 - wildcard_size; 414 415 for (i = wildcard_pos + wildcard_shift; i > wildcard_pos; i--) { 416 size_t j = i - 1; 417 data[j + wildcard_size] = data[j]; 418 data[j] = 0; 419 } 420 } 421 422 success: 423 raddr->version = ip_v6; 424 memcpy(raddr->addr6, data, 16); 425 return EOK; 426 } 427 345 428 /** Parse node address. 346 429 * … … 353 436 int inet_addr_parse(const char *text, inet_addr_t *addr) 354 437 { 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; 438 int rc; 439 440 rc = inet_addr_parse_v4(text, addr, NULL); 441 if (rc == EOK) 442 return EOK; 443 444 rc = inet_addr_parse_v6(text, addr, NULL); 445 if (rc == EOK) 446 return EOK; 447 448 return EINVAL; 377 449 } 378 450 … … 387 459 int inet_naddr_parse(const char *text, inet_naddr_t *naddr) 388 460 { 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) 461 int rc; 462 inet_addr_t addr; 463 int prefix; 464 465 rc = inet_addr_parse_v4(text, &addr, &prefix); 466 if (rc == EOK) { 467 inet_addr_naddr(&addr, prefix, naddr); 468 return EOK; 469 } 470 471 rc = inet_addr_parse_v6(text, &addr, &prefix); 472 if (rc == EOK) { 473 inet_addr_naddr(&addr, prefix, naddr); 474 return EOK; 475 } 476 477 return EINVAL; 478 } 479 480 static int inet_addr_format_v4(addr32_t addr, char **bufp) 481 { 482 int rc; 483 484 rc = asprintf(bufp, "%u.%u.%u.%u", (addr >> 24) & 0xff, 485 (addr >> 16) & 0xff, (addr >> 8) & 0xff, addr & 0xff); 486 if (rc < 0) 487 return ENOMEM; 488 489 return EOK; 490 } 491 492 static int inet_addr_format_v6(const addr128_t addr, char **bufp) 493 { 494 *bufp = (char *) malloc(INET6_ADDRSTRLEN); 495 if (*bufp == NULL) 496 return ENOMEM; 497 498 /* Find the longest zero subsequence */ 499 500 uint16_t zeroes[8]; 501 uint16_t bioctets[8]; 502 503 for (size_t i = 8; i > 0; i--) { 504 size_t j = i - 1; 505 506 bioctets[j] = (addr[j << 1] << 8) | addr[(j << 1) + 1]; 507 508 if (bioctets[j] == 0) { 509 zeroes[j] = 1; 510 if (j < 7) 511 zeroes[j] += zeroes[j + 1]; 512 } else 513 zeroes[j] = 0; 514 } 515 516 size_t wildcard_pos = (size_t) -1; 517 size_t wildcard_size = 0; 518 519 for (size_t i = 0; i < 8; i++) { 520 if (zeroes[i] > wildcard_size) { 521 wildcard_pos = i; 522 wildcard_size = zeroes[i]; 523 } 524 } 525 526 char *cur = *bufp; 527 size_t rest = INET6_ADDRSTRLEN; 528 bool tail_zero = false; 529 int ret; 530 531 for (size_t i = 0; i < 8; i++) { 532 if ((i == wildcard_pos) && (wildcard_size > 1)) { 533 ret = snprintf(cur, rest, ":"); 534 i += wildcard_size - 1; 535 tail_zero = true; 536 } else if (i == 0) { 537 ret = snprintf(cur, rest, "%" PRIx16, bioctets[i]); 538 tail_zero = false; 539 } else { 540 ret = snprintf(cur, rest, ":%" PRIx16, bioctets[i]); 541 tail_zero = false; 542 } 543 544 if (ret < 0) 413 545 return EINVAL; 414 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) 423 return EINVAL; 424 425 memcpy(naddr->addr6, buf, 16); 426 naddr->prefix = prefix; 427 428 break; 429 default: 430 return ENOTSUP; 431 } 432 546 547 cur += ret; 548 rest -= ret; 549 } 550 551 if (tail_zero) 552 (void) snprintf(cur, rest, ":"); 553 433 554 return EOK; 434 555 } … … 446 567 int inet_addr_format(const inet_addr_t *addr, char **bufp) 447 568 { 448 int rc = 0; 449 569 int rc; 570 571 rc = ENOTSUP; 572 450 573 switch (addr->version) { 451 574 case ip_any: 452 575 rc = asprintf(bufp, "none"); 576 if (rc < 0) 577 return ENOMEM; 578 rc = EOK; 453 579 break; 454 580 case ip_v4: 455 rc = asprintf(bufp, "%u.%u.%u.%u", (addr->addr >> 24) & 0xff, 456 (addr->addr >> 16) & 0xff, (addr->addr >> 8) & 0xff, 457 addr->addr & 0xff); 581 rc = inet_addr_format_v4(addr->addr, bufp); 458 582 break; 459 583 case ip_v6: 460 *bufp = (char *) malloc(INET6_ADDRSTRLEN); 461 if (*bufp == NULL) 462 return ENOMEM; 463 464 return inet_ntop(AF_INET6, addr->addr6, *bufp, INET6_ADDRSTRLEN); 465 default: 466 return ENOTSUP; 467 } 468 469 if (rc < 0) 470 return ENOMEM; 471 472 return EOK; 584 rc = inet_addr_format_v6(addr->addr6, bufp); 585 break; 586 } 587 588 return rc; 473 589 } 474 590 … … 485 601 int inet_naddr_format(const inet_naddr_t *naddr, char **bufp) 486 602 { 487 int rc = 0; 488 char prefix[INET_PREFIXSTRSIZE]; 489 603 int rc; 604 char *astr; 605 606 rc = ENOTSUP; 607 490 608 switch (naddr->version) { 491 609 case ip_any: 492 610 rc = asprintf(bufp, "none"); 611 if (rc < 0) 612 return ENOMEM; 613 rc = EOK; 493 614 break; 494 615 case ip_v4: 495 rc = asprintf(bufp, "%" PRIu8 ".%" PRIu8 ".%" PRIu8 ".%" PRIu8 496 "/%" PRIu8, (naddr->addr >> 24) & 0xff, 497 (naddr->addr >> 16) & 0xff, (naddr->addr >> 8) & 0xff, 498 naddr->addr & 0xff, naddr->prefix); 499 break; 500 case ip_v6: 501 *bufp = (char *) malloc(INET6_ADDRSTRLEN + INET_PREFIXSTRSIZE); 502 if (*bufp == NULL) 616 rc = inet_addr_format_v4(naddr->addr, &astr); 617 if (rc != EOK) 503 618 return ENOMEM; 504 505 rc = inet_ntop(AF_INET6, naddr->addr6, *bufp, 506 INET6_ADDRSTRLEN + INET_PREFIXSTRSIZE); 507 if (rc != EOK) { 508 free(*bufp); 509 return rc; 510 } 511 512 rc = snprintf(prefix, INET_PREFIXSTRSIZE, "/%" PRIu8, 513 naddr->prefix); 619 620 rc = asprintf(bufp, "%s/%" PRIu8, astr, naddr->prefix); 514 621 if (rc < 0) { 515 free( *bufp);622 free(astr); 516 623 return ENOMEM; 517 624 } 518 519 str_append(*bufp, INET6_ADDRSTRLEN + INET_PREFIXSTRSIZE, prefix); 520 521 break; 522 default: 523 return ENOTSUP; 524 } 525 526 if (rc < 0) 527 return ENOMEM; 528 529 return EOK; 625 626 rc = EOK; 627 break; 628 case ip_v6: 629 rc = inet_addr_format_v6(naddr->addr6, &astr); 630 if (rc != EOK) 631 return ENOMEM; 632 633 rc = asprintf(bufp, "%s/%" PRIu8, astr, naddr->prefix); 634 if (rc < 0) { 635 free(astr); 636 return ENOMEM; 637 } 638 639 rc = EOK; 640 break; 641 } 642 643 return rc; 530 644 } 531 645 … … 586 700 } 587 701 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 702 void inet_addr_set6(addr128_t v6, inet_addr_t *addr) 595 703 { … … 605 713 } 606 714 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 715 /** @} 680 716 */
Note:
See TracChangeset
for help on using the changeset viewer.