2014-02-10 02:10:30 +01:00
/*************************************************************************/
/* ip_address.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
2017-08-27 14:16:55 +02:00
/* https://godotengine.org */
2014-02-10 02:10:30 +01:00
/*************************************************************************/
2021-01-01 20:13:46 +01:00
/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
2014-02-10 02:10:30 +01:00
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
2018-01-05 00:50:27 +01:00
2014-02-10 02:10:30 +01:00
# include "ip_address.h"
/*
IP_Address : : operator Variant ( ) const {
return operator String ( ) ;
} */
2016-10-18 23:53:18 +02:00
2016-10-19 23:32:36 +02:00
# include <stdio.h>
2017-03-05 16:44:50 +01:00
# include <string.h>
2016-10-18 23:53:18 +02:00
2014-02-10 02:10:30 +01:00
IP_Address : : operator String ( ) const {
2019-05-07 10:17:00 +02:00
if ( wildcard )
return " * " ;
2017-03-05 16:44:50 +01:00
if ( ! valid )
2017-01-17 09:22:56 +01:00
return " " ;
2017-03-05 16:44:50 +01:00
if ( is_ipv4 ( ) )
2016-12-05 16:32:38 +01:00
// IPv4 address mapped to IPv6
2017-03-05 16:44:50 +01:00
return itos ( field8 [ 12 ] ) + " . " + itos ( field8 [ 13 ] ) + " . " + itos ( field8 [ 14 ] ) + " . " + itos ( field8 [ 15 ] ) ;
2016-12-05 16:32:38 +01:00
String ret ;
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < 8 ; i + + ) {
2016-12-05 16:32:38 +01:00
if ( i > 0 )
ret = ret + " : " ;
2017-03-05 16:44:50 +01:00
uint16_t num = ( field8 [ i * 2 ] < < 8 ) + field8 [ i * 2 + 1 ] ;
2016-12-05 16:32:38 +01:00
ret = ret + String : : num_int64 ( num , 16 ) ;
2016-10-19 23:32:36 +02:00
} ;
2016-12-05 16:32:38 +01:00
return ret ;
2014-02-10 02:10:30 +01:00
}
2017-03-05 16:44:50 +01:00
static void _parse_hex ( const String & p_string , int p_start , uint8_t * p_dst ) {
2016-10-18 23:53:18 +02:00
uint16_t ret = 0 ;
2017-03-05 16:44:50 +01:00
for ( int i = p_start ; i < p_start + 4 ; i + + ) {
2016-10-18 23:53:18 +02:00
if ( i > = p_string . length ( ) ) {
break ;
} ;
int n = 0 ;
CharType c = p_string [ i ] ;
if ( c > = ' 0 ' & & c < = ' 9 ' ) {
n = c - ' 0 ' ;
} else if ( c > = ' a ' & & c < = ' f ' ) {
n = 10 + ( c - ' a ' ) ;
} else if ( c > = ' A ' & & c < = ' F ' ) {
n = 10 + ( c - ' A ' ) ;
2016-10-19 23:32:36 +02:00
} else if ( c = = ' : ' ) {
break ;
2016-10-18 23:53:18 +02:00
} else {
2019-08-15 04:57:49 +02:00
ERR_FAIL_MSG ( " Invalid character in IPv6 address: " + p_string + " . " ) ;
2016-10-18 23:53:18 +02:00
} ;
ret = ret < < 4 ;
ret + = n ;
} ;
2016-10-19 23:32:36 +02:00
p_dst [ 0 ] = ret > > 8 ;
p_dst [ 1 ] = ret & 0xff ;
2016-10-18 23:53:18 +02:00
} ;
2017-03-05 16:44:50 +01:00
void IP_Address : : _parse_ipv6 ( const String & p_string ) {
2016-10-18 23:53:18 +02:00
static const int parts_total = 8 ;
2017-03-05 16:44:50 +01:00
int parts [ parts_total ] = { 0 } ;
2016-10-18 23:53:18 +02:00
int parts_count = 0 ;
bool part_found = false ;
bool part_skip = false ;
bool part_ipv4 = false ;
int parts_idx = 0 ;
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < p_string . length ( ) ; i + + ) {
2016-10-18 23:53:18 +02:00
CharType c = p_string [ i ] ;
if ( c = = ' : ' ) {
if ( i = = 0 ) {
continue ; // next must be a ":"
} ;
if ( ! part_found ) {
part_skip = true ;
parts [ parts_idx + + ] = - 1 ;
} ;
part_found = false ;
} else if ( c = = ' . ' ) {
part_ipv4 = true ;
} else if ( ( c > = ' 0 ' & & c < = ' 9 ' ) | | ( c > = ' a ' & & c < = ' f ' ) | | ( c > = ' A ' & & c < = ' F ' ) ) {
if ( ! part_found ) {
parts [ parts_idx + + ] = i ;
part_found = true ;
+ + parts_count ;
} ;
} else {
2019-08-15 04:57:49 +02:00
ERR_FAIL_MSG ( " Invalid character in IPv6 address: " + p_string + " . " ) ;
2016-10-18 23:53:18 +02:00
} ;
} ;
int parts_extra = 0 ;
if ( part_skip ) {
parts_extra = parts_total - parts_count ;
} ;
int idx = 0 ;
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < parts_idx ; i + + ) {
2014-02-10 02:10:30 +01:00
2016-10-18 23:53:18 +02:00
if ( parts [ i ] = = - 1 ) {
2017-03-05 16:44:50 +01:00
for ( int j = 0 ; j < parts_extra ; j + + ) {
2016-10-18 23:53:18 +02:00
field16 [ idx + + ] = 0 ;
} ;
continue ;
} ;
if ( part_ipv4 & & i = = parts_idx - 1 ) {
2017-03-05 16:44:50 +01:00
_parse_ipv4 ( p_string , parts [ i ] , ( uint8_t * ) & field16 [ idx ] ) ; // should be the last one
2016-10-18 23:53:18 +02:00
} else {
2017-03-05 16:44:50 +01:00
_parse_hex ( p_string , parts [ i ] , ( uint8_t * ) & ( field16 [ idx + + ] ) ) ;
2016-10-18 23:53:18 +02:00
} ;
} ;
} ;
2017-03-05 16:44:50 +01:00
void IP_Address : : _parse_ipv4 ( const String & p_string , int p_start , uint8_t * p_ret ) {
2016-10-18 23:53:18 +02:00
String ip ;
if ( p_start ! = 0 ) {
ip = p_string . substr ( p_start , p_string . length ( ) - p_start ) ;
} else {
ip = p_string ;
} ;
int slices = ip . get_slice_count ( " . " ) ;
2019-08-15 04:57:49 +02:00
ERR_FAIL_COND_MSG ( slices ! = 4 , " Invalid IP address string: " + ip + " . " ) ;
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < 4 ; i + + ) {
p_ret [ i ] = ip . get_slicec ( ' . ' , i ) . to_int ( ) ;
2014-02-10 02:10:30 +01:00
}
2016-10-18 23:53:18 +02:00
} ;
void IP_Address : : clear ( ) {
memset ( & field8 [ 0 ] , 0 , sizeof ( field8 ) ) ;
2017-01-17 09:22:56 +01:00
valid = false ;
2017-01-18 04:03:51 +01:00
wildcard = false ;
2016-10-18 23:53:18 +02:00
} ;
2017-03-05 16:44:50 +01:00
bool IP_Address : : is_ipv4 ( ) const {
return ( field32 [ 0 ] = = 0 & & field32 [ 1 ] = = 0 & & field16 [ 4 ] = = 0 & & field16 [ 5 ] = = 0xffff ) ;
2016-12-05 16:32:38 +01:00
}
2017-03-05 16:44:50 +01:00
const uint8_t * IP_Address : : get_ipv4 ( ) const {
2019-09-25 10:28:50 +02:00
ERR_FAIL_COND_V_MSG ( ! is_ipv4 ( ) , & ( field8 [ 12 ] ) , " IPv4 requested, but current IP is IPv6. " ) ; // Not the correct IPv4 (it's an IPv6), but we don't want to return a null pointer risking an engine crash.
2016-12-05 16:32:38 +01:00
return & ( field8 [ 12 ] ) ;
}
void IP_Address : : set_ipv4 ( const uint8_t * p_ip ) {
clear ( ) ;
2017-01-17 09:22:56 +01:00
valid = true ;
2017-03-05 16:44:50 +01:00
field16 [ 5 ] = 0xffff ;
field32 [ 3 ] = * ( ( const uint32_t * ) p_ip ) ;
2016-12-05 16:32:38 +01:00
}
2017-03-05 16:44:50 +01:00
const uint8_t * IP_Address : : get_ipv6 ( ) const {
2016-12-05 16:32:38 +01:00
return field8 ;
}
void IP_Address : : set_ipv6 ( const uint8_t * p_buf ) {
clear ( ) ;
2017-01-17 09:22:56 +01:00
valid = true ;
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < 16 ; i + + )
2016-12-05 16:32:38 +01:00
field8 [ i ] = p_buf [ i ] ;
}
2017-03-05 16:44:50 +01:00
IP_Address : : IP_Address ( const String & p_string ) {
2016-10-18 23:53:18 +02:00
clear ( ) ;
2017-01-18 04:03:51 +01:00
if ( p_string = = " * " ) {
2018-02-21 17:30:55 +01:00
// Wildcard (not a valid IP)
2017-01-18 04:03:51 +01:00
wildcard = true ;
} else if ( p_string . find ( " : " ) > = 0 ) {
2017-01-17 09:22:56 +01:00
// IPv6
2016-10-18 23:53:18 +02:00
_parse_ipv6 ( p_string ) ;
2017-01-17 09:22:56 +01:00
valid = true ;
} else if ( p_string . get_slice_count ( " . " ) = = 4 ) {
// IPv4 (mapped to IPv6 internally)
2016-12-05 16:32:38 +01:00
field16 [ 5 ] = 0xffff ;
_parse_ipv4 ( p_string , 0 , & field8 [ 12 ] ) ;
2017-01-17 09:22:56 +01:00
valid = true ;
} else {
2019-08-15 04:57:49 +02:00
ERR_PRINT ( " Invalid IP address. " ) ;
2017-01-17 09:22:56 +01:00
}
2014-02-10 02:10:30 +01:00
}
2017-03-05 16:44:50 +01:00
_FORCE_INLINE_ static void _32_to_buf ( uint8_t * p_dst , uint32_t p_n ) {
2016-10-19 23:32:36 +02:00
p_dst [ 0 ] = ( p_n > > 24 ) & 0xff ;
p_dst [ 1 ] = ( p_n > > 16 ) & 0xff ;
p_dst [ 2 ] = ( p_n > > 8 ) & 0xff ;
p_dst [ 3 ] = ( p_n > > 0 ) & 0xff ;
} ;
2017-03-05 16:44:50 +01:00
IP_Address : : IP_Address ( uint32_t p_a , uint32_t p_b , uint32_t p_c , uint32_t p_d , bool is_v6 ) {
2016-10-18 23:53:18 +02:00
2016-12-05 16:32:38 +01:00
clear ( ) ;
2017-01-17 09:22:56 +01:00
valid = true ;
2016-12-05 16:32:38 +01:00
if ( ! is_v6 ) {
// Mapped to IPv6
2017-03-05 16:44:50 +01:00
field16 [ 5 ] = 0xffff ;
field8 [ 12 ] = p_a ;
field8 [ 13 ] = p_b ;
field8 [ 14 ] = p_c ;
field8 [ 15 ] = p_d ;
2016-12-05 16:32:38 +01:00
} else {
2016-10-18 23:53:18 +02:00
2016-10-19 23:32:36 +02:00
_32_to_buf ( & field8 [ 0 ] , p_a ) ;
_32_to_buf ( & field8 [ 4 ] , p_b ) ;
_32_to_buf ( & field8 [ 8 ] , p_c ) ;
_32_to_buf ( & field8 [ 12 ] , p_d ) ;
2016-12-05 16:32:38 +01:00
}
2014-02-10 02:10:30 +01:00
}