@@ -192,7 +192,32 @@ pub extern "C-unwind" fn kclvm_net_to_IP4(
192
192
args : * const kclvm_value_ref_t ,
193
193
kwargs : * const kclvm_value_ref_t ,
194
194
) -> * const kclvm_value_ref_t {
195
- kclvm_net_IP_string ( ctx, args, kwargs)
195
+ let args = ptr_as_ref ( args) ;
196
+ let kwargs = ptr_as_ref ( kwargs) ;
197
+ let ctx = mut_ptr_as_ref ( ctx) ;
198
+ if let Some ( ip) = get_call_arg_str ( args, kwargs, 0 , Some ( "ip" ) ) {
199
+ match Ipv4Addr :: from_str ( ip. as_ref ( ) ) {
200
+ Ok ( addr) => {
201
+ let s = format ! ( "{addr}" ) ;
202
+ return ValueRef :: str ( s. as_ref ( ) ) . into_raw ( ctx) ;
203
+ }
204
+ Err ( _e) => match Ipv6Addr :: from_str ( ip. as_ref ( ) ) {
205
+ Ok ( addr) => {
206
+ if let Some ( v4) = addr. to_ipv4 ( ) {
207
+ let s = format ! ( "{v4}" ) ;
208
+ return ValueRef :: str ( s. as_ref ( ) ) . into_raw ( ctx) ;
209
+ }
210
+ let s = format ! ( "can not parse {} ipv6 to ipv4!" , ip) ;
211
+ return ValueRef :: str ( s. as_ref ( ) ) . into_raw ( ctx) ;
212
+ }
213
+ Err ( e) => {
214
+ let s = format ! ( "can not both parse {} to ipv6 and ipv4,err:{}" , ip, e) ;
215
+ return ValueRef :: str ( s. as_ref ( ) ) . into_raw ( ctx) ;
216
+ }
217
+ } ,
218
+ }
219
+ }
220
+ panic ! ( "IP_string() missing 1 required positional argument: 'ip'" ) ;
196
221
}
197
222
198
223
// to_IP16(ip) -> int
@@ -204,7 +229,33 @@ pub extern "C-unwind" fn kclvm_net_to_IP16(
204
229
args : * const kclvm_value_ref_t ,
205
230
kwargs : * const kclvm_value_ref_t ,
206
231
) -> * const kclvm_value_ref_t {
207
- kclvm_net_IP_string ( ctx, args, kwargs)
232
+ let args = ptr_as_ref ( args) ;
233
+ let kwargs = ptr_as_ref ( kwargs) ;
234
+ let ctx = mut_ptr_as_ref ( ctx) ;
235
+ if let Some ( ip) = get_call_arg_str ( args, kwargs, 0 , Some ( "ip" ) ) {
236
+ match Ipv6Addr :: from_str ( ip. as_ref ( ) ) {
237
+ Ok ( addr) => {
238
+ let s = format ! ( "{addr}" ) ;
239
+ return ValueRef :: str ( s. as_ref ( ) ) . into_raw ( ctx) ;
240
+ }
241
+ Err ( e) => {
242
+ // print!("can not parse {} to ipv6:{},parsing {} to ipv4", ip, e, ip);
243
+ match Ipv4Addr :: from_str ( ip. as_ref ( ) ) {
244
+ Ok ( addr) => {
245
+ // Convert IPv4 to IPv6-mapped address (::ffff:0:0/96)
246
+ let v6 = addr. to_ipv6_mapped ( ) ;
247
+ let s = format ! ( "{v6}" ) ;
248
+ return ValueRef :: str ( s. as_ref ( ) ) . into_raw ( ctx) ;
249
+ }
250
+ Err ( e) => {
251
+ let s = format ! ( "can not both parse {} to ipv6 and ipv4,err:{}" , ip, e) ;
252
+ return ValueRef :: str ( s. as_ref ( ) ) . into_raw ( ctx) ;
253
+ }
254
+ }
255
+ }
256
+ }
257
+ }
258
+ panic ! ( "IP_string() missing 1 required positional argument: 'ip'" ) ;
208
259
}
209
260
210
261
// IP_string(ip: str) -> str
@@ -911,6 +962,79 @@ pub extern "C-unwind" fn kclvm_net_CIDR_netmask(
911
962
mod test_net {
912
963
use super :: * ;
913
964
965
+ #[ test]
966
+ #[ allow( non_snake_case) ]
967
+ fn test_to_ip4 ( ) {
968
+ let cases = [
969
+ ( "::FFFF:192.168.1.10" , "192.168.1.10" ) ,
970
+ (
971
+ "::FFFF:192.168.x.10" ,
972
+ "can not both parse ::FFFF:192.168.x.10 to ipv6 and ipv4,err:invalid IPv6 address syntax" ,
973
+ ) ,
974
+ ( "::FFFF:10.0.0.1" , "10.0.0.1" ) ,
975
+ ( "::FFFF:172.16.0.1" , "172.16.0.1" ) ,
976
+ ( "::FFFF:127.0.0.1" , "127.0.0.1" ) ,
977
+ ( "0000:0000:0000:0000:0000:FFFF:0A00:0001" , "10.0.0.1" ) ,
978
+ ( "::FFFF:224.0.0.1" , "224.0.0.1" ) ,
979
+ (
980
+ "::FFFF:invalid.ip" ,
981
+ "can not both parse ::FFFF:invalid.ip to ipv6 and ipv4,err:invalid IPv6 address syntax"
982
+ ) ,
983
+ // IPv4-mapped IPv6 addresses
984
+ ( "::FFFF:0A00:0001" , "10.0.0.1" ) ,
985
+ ( "0:0:0:0:0:FFFF:AC10:0001" , "172.16.0.1" ) ,
986
+ ] ;
987
+ let mut ctx = Context :: default ( ) ;
988
+ for ( ip6, expected) in cases. iter ( ) {
989
+ unsafe {
990
+ let actual = & * kclvm_net_to_IP4 (
991
+ & mut ctx,
992
+ & ValueRef :: list ( Some ( & [ & ValueRef :: str ( ip6) ] ) ) ,
993
+ & ValueRef :: dict ( None ) ,
994
+ ) ;
995
+ assert_eq ! ( & ValueRef :: str ( expected) , actual, "{} positional" , ip6, ) ;
996
+ }
997
+ }
998
+ }
999
+
1000
+ #[ test]
1001
+ #[ allow( non_snake_case) ]
1002
+ fn test_to_ip6 ( ) {
1003
+ let cases = [
1004
+ ( "192.168.1.10" , "::ffff:192.168.1.10" ) ,
1005
+ (
1006
+ "192.168.x.10" ,
1007
+ "can not both parse 192.168.x.10 to ipv6 and ipv4,err:invalid IPv4 address syntax" ,
1008
+ ) ,
1009
+ ( "10.0.0.1" , "::ffff:10.0.0.1" ) ,
1010
+ ( "172.16.0.1" , "::ffff:172.16.0.1" ) ,
1011
+ ( "127.0.0.1" , "::ffff:127.0.0.1" ) ,
1012
+ ( "224.0.0.1" , "::ffff:224.0.0.1" ) ,
1013
+ (
1014
+ "invalid.ip" ,
1015
+ "can not both parse invalid.ip to ipv6 and ipv4,err:invalid IPv4 address syntax" ,
1016
+ ) ,
1017
+ // IPv6 addresses
1018
+ ( "2001:db8::1" , "2001:db8::1" ) ,
1019
+ ( "::1" , "::1" ) ,
1020
+ (
1021
+ "2001:db8:::1" ,
1022
+ "can not both parse 2001:db8:::1 to ipv6 and ipv4,err:invalid IPv4 address syntax" ,
1023
+ ) ,
1024
+ ] ;
1025
+ let mut ctx = Context :: default ( ) ;
1026
+ for ( ip4, expected) in cases. iter ( ) {
1027
+ unsafe {
1028
+ let actual = & * kclvm_net_to_IP16 (
1029
+ & mut ctx,
1030
+ & ValueRef :: list ( Some ( & [ & ValueRef :: str ( ip4) ] ) ) ,
1031
+ & ValueRef :: dict ( None ) ,
1032
+ ) ;
1033
+ assert_eq ! ( & ValueRef :: str ( expected) , actual, "{} positional" , ip4, ) ;
1034
+ }
1035
+ }
1036
+ }
1037
+
914
1038
#[ test]
915
1039
fn test_split_host_port ( ) {
916
1040
let cases = [
@@ -950,7 +1074,6 @@ mod test_net {
950
1074
}
951
1075
}
952
1076
}
953
-
954
1077
#[ test]
955
1078
fn test_split_host_port_invalid ( ) {
956
1079
let prev_hook = std:: panic:: take_hook ( ) ;
0 commit comments