Changeset 048cd69 in mainline for uspace/lib/c/generic/inet/addr.c
- Timestamp:
- 2015-06-07T15:41:04Z (10 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- 204ba47
- Parents:
- 4d11204 (diff), c3f7d37 (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
r4d11204 r048cd69 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') 309 break; 310 311 if (*cur != '.') 312 return EINVAL; 313 314 if (i < 4) 315 cur++; 316 } 317 318 if (prefix != NULL) { 319 *prefix = strtoul(cur, &cur, 10); 320 if (*prefix > 32) 321 return EINVAL; 322 } 323 324 if (i != 4 || (*cur != '\0')) 325 return EINVAL; 326 327 raddr->version = ip_v4; 328 raddr->addr = a; 329 330 return EOK; 331 } 332 333 static int inet_addr_parse_v6(const char *str, inet_addr_t *raddr, int *prefix) 334 { 335 uint8_t data[16]; 336 337 memset(data, 0, 16); 338 339 const char *cur = str; 340 size_t i = 0; 341 size_t wildcard_pos = (size_t) -1; 342 size_t wildcard_size = 0; 343 344 /* Handle initial wildcard */ 345 if ((str[0] == ':') && (str[1] == ':')) { 346 cur = str + 2; 347 wildcard_pos = 0; 348 wildcard_size = 16; 349 350 /* Handle the unspecified address */ 351 if (*cur == '\0') 352 goto success; 353 } 354 355 while (i < 16) { 356 uint16_t bioctet; 357 int rc = str_uint16_t(cur, &cur, 16, false, &bioctet); 358 if (rc != EOK) 359 return rc; 360 361 data[i] = (bioctet >> 8) & 0xff; 362 data[i + 1] = bioctet & 0xff; 363 364 if (wildcard_pos != (size_t) -1) { 365 if (wildcard_size < 2) 366 return EINVAL; 367 368 wildcard_size -= 2; 369 } 370 371 i += 2; 372 373 if (*cur != ':') 374 break; 375 376 if (i < 16) { 377 cur++; 378 379 /* Handle wildcard */ 380 if (*cur == ':') { 381 if (wildcard_pos != (size_t) -1) 382 return EINVAL; 383 384 wildcard_pos = i; 385 wildcard_size = 16 - i; 386 cur++; 387 388 if (*cur == '\0' || *cur == '/') 389 break; 390 } 391 } 392 } 393 394 if (prefix != NULL) { 395 if (*cur != '/') 396 return EINVAL; 397 cur++; 398 399 *prefix = strtoul(cur, (char **)&cur, 10); 400 if (*prefix > 128) 401 return EINVAL; 402 } 403 404 if (*cur != '\0') 405 return EINVAL; 406 407 /* Create wildcard positions */ 408 if ((wildcard_pos != (size_t) -1) && (wildcard_size > 0)) { 409 size_t wildcard_shift = 16 - wildcard_size; 410 411 for (i = wildcard_pos + wildcard_shift; i > wildcard_pos; i--) { 412 size_t j = i - 1; 413 data[j + wildcard_size] = data[j]; 414 data[j] = 0; 415 } 416 } 417 418 success: 419 raddr->version = ip_v6; 420 memcpy(raddr->addr6, data, 16); 421 return EOK; 422 } 423 345 424 /** Parse node address. 346 425 * … … 353 432 int inet_addr_parse(const char *text, inet_addr_t *addr) 354 433 { 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; 434 int rc; 435 436 rc = inet_addr_parse_v4(text, addr, NULL); 437 if (rc == EOK) 438 return EOK; 439 440 rc = inet_addr_parse_v6(text, addr, NULL); 441 if (rc == EOK) 442 return EOK; 443 444 return EINVAL; 377 445 } 378 446 … … 387 455 int inet_naddr_parse(const char *text, inet_naddr_t *naddr) 388 456 { 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) 457 int rc; 458 inet_addr_t addr; 459 int prefix; 460 461 rc = inet_addr_parse_v4(text, &addr, &prefix); 462 if (rc == EOK) { 463 inet_addr_naddr(&addr, prefix, naddr); 464 return EOK; 465 } 466 467 rc = inet_addr_parse_v6(text, &addr, &prefix); 468 if (rc == EOK) { 469 inet_addr_naddr(&addr, prefix, naddr); 470 return EOK; 471 } 472 473 return EINVAL; 474 } 475 476 static int inet_addr_format_v4(addr32_t addr, char **bufp) 477 { 478 int rc; 479 480 rc = asprintf(bufp, "%u.%u.%u.%u", (addr >> 24) & 0xff, 481 (addr >> 16) & 0xff, (addr >> 8) & 0xff, addr & 0xff); 482 if (rc < 0) 483 return ENOMEM; 484 485 return EOK; 486 } 487 488 static int inet_addr_format_v6(const addr128_t addr, char **bufp) 489 { 490 *bufp = (char *) malloc(INET6_ADDRSTRLEN); 491 if (*bufp == NULL) 492 return ENOMEM; 493 494 /* Find the longest zero subsequence */ 495 496 uint16_t zeroes[8]; 497 uint16_t bioctets[8]; 498 499 for (size_t i = 8; i > 0; i--) { 500 size_t j = i - 1; 501 502 bioctets[j] = (addr[j << 1] << 8) | addr[(j << 1) + 1]; 503 504 if (bioctets[j] == 0) { 505 zeroes[j] = 1; 506 if (j < 7) 507 zeroes[j] += zeroes[j + 1]; 508 } else 509 zeroes[j] = 0; 510 } 511 512 size_t wildcard_pos = (size_t) -1; 513 size_t wildcard_size = 0; 514 515 for (size_t i = 0; i < 8; i++) { 516 if (zeroes[i] > wildcard_size) { 517 wildcard_pos = i; 518 wildcard_size = zeroes[i]; 519 } 520 } 521 522 char *cur = *bufp; 523 size_t rest = INET6_ADDRSTRLEN; 524 bool tail_zero = false; 525 int ret; 526 527 for (size_t i = 0; i < 8; i++) { 528 if ((i == wildcard_pos) && (wildcard_size > 1)) { 529 ret = snprintf(cur, rest, ":"); 530 i += wildcard_size - 1; 531 tail_zero = true; 532 } else if (i == 0) { 533 ret = snprintf(cur, rest, "%" PRIx16, bioctets[i]); 534 tail_zero = false; 535 } else { 536 ret = snprintf(cur, rest, ":%" PRIx16, bioctets[i]); 537 tail_zero = false; 538 } 539 540 if (ret < 0) 413 541 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 542 543 cur += ret; 544 rest -= ret; 545 } 546 547 if (tail_zero) 548 (void) snprintf(cur, rest, ":"); 549 433 550 return EOK; 434 551 } … … 446 563 int inet_addr_format(const inet_addr_t *addr, char **bufp) 447 564 { 448 int rc = 0; 449 565 int rc; 566 567 rc = ENOTSUP; 568 450 569 switch (addr->version) { 451 570 case ip_any: 452 571 rc = asprintf(bufp, "none"); 572 if (rc < 0) 573 return ENOMEM; 574 rc = EOK; 453 575 break; 454 576 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); 577 rc = inet_addr_format_v4(addr->addr, bufp); 458 578 break; 459 579 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; 580 rc = inet_addr_format_v6(addr->addr6, bufp); 581 break; 582 } 583 584 return rc; 473 585 } 474 586 … … 485 597 int inet_naddr_format(const inet_naddr_t *naddr, char **bufp) 486 598 { 487 int rc = 0; 488 char prefix[INET_PREFIXSTRSIZE]; 489 599 int rc; 600 char *astr; 601 602 rc = ENOTSUP; 603 490 604 switch (naddr->version) { 491 605 case ip_any: 492 606 rc = asprintf(bufp, "none"); 607 if (rc < 0) 608 return ENOMEM; 609 rc = EOK; 493 610 break; 494 611 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) 612 rc = inet_addr_format_v4(naddr->addr, &astr); 613 if (rc != EOK) 503 614 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); 615 616 rc = asprintf(bufp, "%s/%" PRIu8, astr, naddr->prefix); 514 617 if (rc < 0) { 515 free( *bufp);618 free(astr); 516 619 return ENOMEM; 517 620 } 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; 621 622 rc = EOK; 623 break; 624 case ip_v6: 625 rc = inet_addr_format_v6(naddr->addr6, &astr); 626 if (rc != EOK) 627 return ENOMEM; 628 629 rc = asprintf(bufp, "%s/%" PRIu8, astr, naddr->prefix); 630 if (rc < 0) { 631 free(astr); 632 return ENOMEM; 633 } 634 635 rc = EOK; 636 break; 637 } 638 639 return rc; 530 640 } 531 641 … … 586 696 } 587 697 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 698 void inet_addr_set6(addr128_t v6, inet_addr_t *addr) 595 699 { … … 605 709 } 606 710 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 711 /** @} 680 712 */
Note:
See TracChangeset
for help on using the changeset viewer.