%% options copyright owner = Dirk Krause copyright year = 2015-xxxx license = bsd %% module #include "dk4sock.h" #include "dk4maaul.h" #include "dk4maaus.h" $!trace-include #if !DK4_HAVE_INET_PTON /** Character classes. */ enum { /** Any character not rom the types below. */ INPUT_ANY = 0 , /** Digit. */ INPUT_DIGIT , /** Separator (dot for IPv4, colon for IPv6). */ INPUT_SEP , /** End of input reached. */ INPUT_END }; /** States while reading IPv4. */ enum { /** Nothing processed yet. */ S4_INIT = 0 , /** Previous character was a separator. */ S4_SEP , /** Previous character was digit. */ S4_DIG , /** Successfully finished IP address retrieval. */ S4_FINISHED , /** Error found in previous input. */ S4_ERROR }; static int dk4socket_classify_input_char( char c, int ipv6, unsigned short *valptr ) { int back = INPUT_ANY; switch (c) { case ':' : { if (0 != ipv6) { back = INPUT_SEP; } } break; case '.' : { if (0 == ipv6) { back = INPUT_SEP; } } break; case '0': { back = INPUT_DIGIT; *valptr = 0; } break; case '1': { back = INPUT_DIGIT; *valptr = 1; } break; case '2': { back = INPUT_DIGIT; *valptr = 2; } break; case '3': { back = INPUT_DIGIT; *valptr = 3; } break; case '4': { back = INPUT_DIGIT; *valptr = 4; } break; case '5': { back = INPUT_DIGIT; *valptr = 5; } break; case '6': { back = INPUT_DIGIT; *valptr = 6; } break; case '7': { back = INPUT_DIGIT; *valptr = 7; } break; case '8': { back = INPUT_DIGIT; *valptr = 8; } break; case '9': { back = INPUT_DIGIT; *valptr = 9; } break; case 'a': { if (0 != ipv6) { back = INPUT_DIGIT; *valptr = 10; } } break; case 'A': { if (0 != ipv6) { back = INPUT_DIGIT; *valptr = 10; } } break; case 'b': { if (0 != ipv6) { back = INPUT_DIGIT; *valptr = 11; } } break; case 'B': { if (0 != ipv6) { back = INPUT_DIGIT; *valptr = 11; } } break; case 'c': { if (0 != ipv6) { back = INPUT_DIGIT; *valptr = 12; } } break; case 'C': { if (0 != ipv6) { back = INPUT_DIGIT; *valptr = 12; } } break; case 'd': { if (0 != ipv6) { back = INPUT_DIGIT; *valptr = 13; } } break; case 'D': { if (0 != ipv6) { back = INPUT_DIGIT; *valptr = 13; } } break; case 'e': { if (0 != ipv6) { back = INPUT_DIGIT; *valptr = 14; } } break; case 'E': { if (0 != ipv6) { back = INPUT_DIGIT; *valptr = 14; } } break; case 'f': { if (0 != ipv6) { back = INPUT_DIGIT; *valptr = 15; } } break; case 'F': { if (0 != ipv6) { back = INPUT_DIGIT; *valptr = 15; } } break; } return back; } #if DK4_HAVE_STRUCT_SOCKADDR_IN6 /** States while reading IPv4. */ enum { /** Nothing processed yet. */ S6_INIT = 0 , /** Previous character was a separator. */ S6_SEP , /** Previous two characters were separators. */ S6_DSEP , /** Previous character was digit. */ S6_DIG , /** Successfully finished IP address retrieval. */ S6_FINISHED , /** Error found in previous input. */ S6_ERROR }; static int dk4socket_my_ip6_pton( void *pAddr, size_t szAddr, const char *src, dk4_er_t *erp ) { dk4_er_t er; unsigned short left[8]; /* Values for left side */ unsigned short right[8]; /* Values for right side */ struct in6_addr *inp6 = NULL; /* Result */ int isright = 0; /* Flag: Already on right side */ int hl = 0; /* Number of values on left side */ int hr = 0; /* Number of values on right side */ int icl = 0; /* Input character class */ int cc = 1; /* Flag: Can continue */ int st = S6_INIT; /* Current state */ int back = DK4_SOCKET_RESULT_FAILED; int i = 0; /* Index to fill address */ unsigned short curval = 0; /* Value collected so far */ unsigned short us = 0; /* Current character value */ do { if ('\0' == *src) { icl = INPUT_END; } else { icl = dk4socket_classify_input_char(*src, 1, &us); } switch (st) { case S6_INIT : { switch (icl) { case INPUT_DIGIT : { curval = us; st = S6_DIG; } break; case INPUT_SEP : { st = S6_SEP; } break; default : { st = S6_ERROR; cc = -1; } break; } } break; case S6_SEP : { switch (icl) { case INPUT_DIGIT : { curval = us; st = S6_DIG; } break; case INPUT_SEP : { st = S6_DSEP; if (0 == isright) { isright = 1; } else { st = S6_ERROR; cc = -1; } } break; default : { st = S6_ERROR; cc = -1; } break; } } break; case S6_DSEP : { switch (icl) { case INPUT_DIGIT : { curval = us; st = S6_DIG; } break; case INPUT_END : { st = S6_FINISHED; } break; default : { st = S6_ERROR; cc = -1; } break; } } break; case S6_DIG : { switch (icl) { case INPUT_DIGIT : { dk4error_init(&er); curval = dk4ma_ushort_add( dk4ma_ushort_mul(curval, 16UL, &er), us, &er ); if (DK4_E_NONE != er.ec) { st = S6_ERROR; cc = -1; } } break; case INPUT_SEP : { if (0 != isright) { if (8 > hr) { right[hr++] = curval; st = S6_SEP; } else { st = S6_ERROR; cc = -1; } } else { if (8 > hl) { left[hl++] = curval; st = S6_SEP; } else { st = S6_ERROR; cc = -1; } } } break; case INPUT_END : { if (0 != isright) { if (8 > hr) { right[hr++] = curval; st = S6_FINISHED; cc = 0; } else { st = S6_ERROR; cc = -1; } } else { if (8 > hl) { left[hl++] = curval; st = S6_FINISHED; cc = 0; } else { st = S6_ERROR; cc = -1; } } } break; default : { st = S6_ERROR; cc = -1; } break; } } break; } src++; if ((1 == cc) && (INPUT_END == icl)) { cc = 0; } } while (1 == cc); if ((0 == cc) && (S6_FINISHED == st)) { if (9 > (hl + hr)) { inp6 = (struct in6_addr *)pAddr; for (i = 0; i < 8; i++) { #if DK4_ON_WINDOWS inp6->u.Word[i] = dk4socket_htons(0); #else inp6->s6_addr16[i] = dk4socket_htons(0); #endif } for (i = 0; i < hl; i++) { #if DK4_ON_WINDOWS inp6->u.Word[i] = dk4socket_htons(left[i]); #else inp6->s6_addr16[i] = dk4socket_htons(left[i]); #endif } for (i = 0; i < hr; i++) { #if DK4_ON_WINDOWS inp6->u.Word[8 - hr + i ] = dk4socket_htons(right[i]); #else inp6->s6_addr16[8 - hr + i] = dk4socket_htons(right[i]); #endif } back = DK4_SOCKET_RESULT_SUCCESS; } else { dk4error_set_simple_error_code(erp, DK4_E_SYNTAX); } } else { dk4error_set_simple_error_code(erp, DK4_E_SYNTAX); } return back; } #endif static int dk4socket_my_ip4_pton( void *pAddr, size_t szAddr, const char *src, dk4_er_t *erp ) { dk4_er_t er; struct in_addr *pin4; unsigned long curval = 0UL; unsigned long result = 0UL; int back = DK4_SOCKET_RESULT_FAILED; int cc = 1; int icl = 0; int st = S4_INIT; int curnum = 0; unsigned short us = 0; $? "+ dk4socket_my_ip4_pton \"%!8s\"", src do { us = 0; if ('\0' == *src) { icl = INPUT_END; } else { icl = dk4socket_classify_input_char(*src, 0, &us); } switch (icl) { case INPUT_DIGIT : { switch (st) { case S4_INIT: { curval = (unsigned long)us; st = S4_DIG; } break; case S4_SEP : { curval = (unsigned long)us; st = S4_DIG; } break; case S4_DIG : { dk4error_init(&er); curval = dk4ma_ulong_add( dk4ma_ulong_mul(curval, 10UL, &er), (unsigned long)us, &er ); if (DK4_E_NONE != er.ec) { st = S4_ERROR; cc = -1; } } break; } } break; case INPUT_SEP : { switch (st) { case S4_INIT: { st = S4_ERROR; cc = -1; } break; case S4_SEP : { st = S4_ERROR; cc = -1; } break; case S4_DIG : { if (256UL > curval) { switch (curnum++) { case 0: { result = ((curval << 24) & 0xFF000000UL); st = S4_SEP; curval = 0UL; } break; case 1: { result |= ((curval << 16) & 0x00FF0000UL); st = S4_SEP; curval = 0UL; } break; case 2: { result |= ((curval << 8) & 0x0000FF00UL); st = S4_SEP; curval = 0UL; } break; default: { st = S4_ERROR; cc = -1; } break; } } else { st = S4_ERROR; cc = -1; } } break; } } break; case INPUT_END : { switch (st) { case S4_INIT: { st = S4_ERROR; cc = -1; } break; case S4_SEP : { st = S4_ERROR; cc = -1; } break; case S4_DIG : { st = S4_ERROR; cc = -1; if (3 == curnum) { if (256UL > curval) { result |= curval; cc = 0; st = S4_FINISHED; } } } break; } } break; default : { st = S4_ERROR; cc = -1; } break; } src++; } while(1 == cc); if ((0 == cc) && (S4_FINISHED == st)) { pin4 = (struct in_addr *)pAddr; pin4->s_addr = dk4socket_htonl(result); back = DK4_SOCKET_RESULT_FAILED; $? ". result = %lu.%lu.%lu.%lu", ((result >> 24) & 0x000000FFUL), ((result >> 16) & 0x000000FFUL), ((result >> 8) & 0x000000FFUL), (result & 0x000000FFUL) } else { dk4error_set_simple_error_code(erp, DK4_E_SYNTAX); $? ". failed" } $? "- dk4socket_my_ip4_pton %d", back return back; } static int dk4socket_my_inet_pton( void *pAddr, size_t szAddr, int afam, const char *src, dk4_er_t *erp ) { int back = DK4_SOCKET_RESULT_FAILED; #if DK4_HAVE_STRUCT_SOCKADDR_IN6 if (AF_INET6 == afam) { back = dk4socket_my_ip6_pton(pAddr, szAddr, src, erp); } else { #endif back = dk4socket_my_ip4_pton(pAddr, szAddr, src, erp); #if DK4_HAVE_STRUCT_SOCKADDR_IN6 } #endif return back; } #endif int dk4socket_c8_inet_pton( void *pAddr, size_t szAddr, int afam, const char *src, dk4_er_t *erp ) { #if DK4_HAVE_INET_PTON /* +++++ +inet_pton */ int back = DK4_SOCKET_RESULT_FAILED; int res; if ((NULL != pAddr) && (0 < szAddr) && (NULL != src)) { switch (afam) { case AF_INET : { if (sizeof(struct in_addr) == szAddr) { back = DK4_SOCKET_RESULT_SUCCESS; } } break; #if DK4_HAVE_STRUCT_SOCKADDR_IN6 case AF_INET6 : { if (sizeof(struct in6_addr) == szAddr) { back = DK4_SOCKET_RESULT_SUCCESS; } } break; #endif } if (DK4_SOCKET_RESULT_SUCCESS == back) { back = DK4_SOCKET_RESULT_FAILED; dk4socket_error_reset(); res = inet_pton(afam, src, pAddr); switch (res) { case 0 : { dk4error_set_simple_error_code(erp, DK4_E_SYNTAX); } break; case -1 : { dk4socket_error_report(erp, DK4_E_SOCKET_INET_PTON); } break; default : { back = DK4_SOCKET_RESULT_SUCCESS; } break; } } else { dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS); } } else { dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS); } return back; /* ----- +inet_pton */ #else /* +++++ -inet_pton */ int back = DK4_SOCKET_RESULT_FAILED; if ((NULL != pAddr) && (0 < szAddr) && (NULL != src)) { switch (afam) { case AF_INET : { if (sizeof(struct in_addr) == szAddr) { back = DK4_SOCKET_RESULT_SUCCESS; } } break; #if DK4_HAVE_STRUCT_SOCKADDR_IN6 case AF_INET6 : { if (sizeof(struct in6_addr) == szAddr) { back = DK4_SOCKET_RESULT_SUCCESS; } } break; #endif } if (DK4_SOCKET_RESULT_SUCCESS == back) { back = dk4socket_my_inet_pton(pAddr, szAddr, afam, src, erp); } else { dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS); } } else { dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS); } return back; /* ----- -inet_pton */ #endif }