Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
OpenHarmony
Docs
提交
8ac74376
D
Docs
项目概览
OpenHarmony
/
Docs
大约 2 年 前同步成功
通知
161
Star
293
Fork
28
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
D
Docs
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
提交
8ac74376
编写于
7月 18, 2023
作者:
X
xujie
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Add Native c++
Change-Id: I85b4755079f3de49536fe8c86bd2d5e630fc3e4d Signed-off-by:
N
xujie
<
xujie223@huawei.com
>
上级
c686ac07
变更
1
隐藏空白更改
内联
并排
Showing
1 changed file
with
310 addition
and
86 deletion
+310
-86
zh-cn/application-dev/connectivity/net-vpn.md
zh-cn/application-dev/connectivity/net-vpn.md
+310
-86
未找到文件。
zh-cn/application-dev/connectivity/net-vpn.md
浏览文件 @
8ac74376
...
@@ -26,102 +26,326 @@ VPN即虚拟专网(VPN-Virtual Private Network)在公用网络上建立专
...
@@ -26,102 +26,326 @@ VPN即虚拟专网(VPN-Virtual Private Network)在公用网络上建立专
3.
建立一个VPN网络。
3.
建立一个VPN网络。
4.
处理虚拟网卡的数据,如:读写操作。
4.
处理虚拟网卡的数据,如:读写操作。
```
js
本示例通过 Native C++ 的方式开发应用程序,Native C++ 可参考:
[
简易Native C++ 示例(ArkTS)(API9)
](
https://gitee.com/openharmony/codelabs/tree/master/NativeAPI/NativeTemplateDemo
)
import
vpn
from
'
@ohos.net.vpn
'
// FA模型获取context
### js 相关的代码
import
featureAbility
from
'
@ohos.ability.featureAbility
'
;
let
context
=
featureAbility
.
getContext
();
// Stage模型获取context
```
js
import
hilog
from
'
@ohos.hilog
'
;
import
vpn
from
'
@ohos.net.vpn
'
;
import
UIAbility
from
'
@ohos.app.ability.UIAbility
'
;
import
UIAbility
from
'
@ohos.app.ability.UIAbility
'
;
import
vpn_client
from
"
libvpn_client.so
"
class
EntryAbility
extends
UIAbility
{
class
EntryAbility
extends
UIAbility
{
onWindowStageCreate
(
windowStage
){
onWindowStageCreate
(
windowStage
)
{
globalThis
.
context
=
this
.
context
;
globalThis
.
context
=
this
.
context
;
}
}
}
}
let
context
=
globalThis
.
context
;
let
TunnelFd
=
-
1
// 获取VpnConnection对象
let
VpnConnection
=
vpn
.
createVpnConnection
(
globalThis
.
context
)
VpnConnection
=
vpn
.
createVpnConnection
(
context
);
console
.
info
(
"
vpn onInit:
"
+
JSON
.
stringify
(
VpnConnection
));
@
Entry
@
Component
// 建立TCP 隧道
struct
Index
{
import
socket
from
"
@ohos.net.socket
"
;
@
State
message
:
string
=
'
Toy VPN
'
var
tcp
=
socket
.
constructTCPSocketInstance
();
tcp
.
bind
({
CreateTunnel
()
{
address
:
"
0.0.0.0
"
,
TunnelFd
=
vpn_client
.
tcpConnect
(
"
192.168.43.208
"
,
8888
)
family
:
1
})
let
connectAddress
=
{
address
:
"
192.168.1.11
"
,
port
:
8888
,
family
:
1
};
tcp
.
connect
({
address
:
connectAddress
,
timeout
:
6000
})
tcp
.
getSocketFd
().
then
((
tunnelfd
)
=>
{
console
.
info
(
"
tunenlfd:
"
+
tunnelfd
);
VpnConnection
.
protect
(
tunnelfd
,
(
error
,
data
)
=>
{
console
.
info
(
JSON
.
stringify
(
error
));
console
.
info
(
JSON
.
stringify
(
data
));
})
})
// 建立 VPN 网络
let
config
=
{
addresses
:
[{
address
:
{
address
:
"
10.0.0.5
"
,
family
:
1
},
prefixLength
:
24
,
}],
routes
:
[],
mtu
:
1400
,
dnsAddresses
:[
"
114.114.114.114
"
],
acceptedApplications
:[],
refusedApplications
:[]
}
let
tunfd
=
0
VpnConnection
.
setUp
(
config
).
then
((
data
)
=>
{
console
.
info
(
"
setUp success, tunfd:
"
+
JSON
.
stringify
(
data
))
tunfd
=
data
StartReadFromTun
(
data
)
}).
catch
(
err
=>
{
console
.
info
(
"
setUp fail
"
+
JSON
.
stringify
(
err
))
})
// 处理虚拟网卡的数据
import
fs
from
'
@ohos.file.fs
'
;
async
function
StartReadFromTun
(
tunFd
)
{
let
buf
=
new
ArrayBuffer
(
4096
);
while
(
tunFd
)
{
await
sleep
(
1
)
fs
.
read
(
tunFd
,
buf
).
then
((
readLen
)
=>
{
console
.
info
(
"
read file data succeed, len:
"
,
readLen
);
await
tcp
.
send
({
data
:
buffer
.
slice
(
0
,
readLen
)
})
}).
catch
((
err
)
=>
{
console
.
info
(
"
read file data failed with error message:
"
+
err
.
message
+
"
, error code:
"
+
err
.
code
);
});
}
}
}
tcp
.
on
(
'
message
'
,
(
data
)
=>
{
Protect
()
{
console
.
log
(
"
on message:
"
+
JSON
.
stringify
(
data
.
message
)
+
"
, remoteInfo:
"
+
JSON
.
stringify
(
data
.
remoteInfo
));
console
.
info
(
"
vpn Protect
"
)
if
(
data
.
message
)
{
VpnConnection
.
protect
(
TunnelFd
).
then
(
function
()
{
if
(
!
tunfd
)
{
console
.
info
(
"
vpn Protect Success
"
)
console
.
info
(
"
tunfd is null
"
)
}).
catch
(
function
(
err
)
{
return
;
console
.
info
(
"
vpn Protect Failed
"
+
JSON
.
stringify
(
err
))
})
}
SetupVpn
()
{
console
.
info
(
"
vpn SetupVpn
"
)
let
config
=
{
addresses
:
[{
address
:
{
address
:
"
10.0.0.5
"
,
family
:
1
},
prefixLength
:
24
,
}],
routes
:
[],
mtu
:
1400
,
dnsAddresses
:
[
"
114.114.114.114
"
],
acceptedApplications
:
[],
refusedApplications
:
[]
}
try
{
VpnConnection
.
setUp
(
config
,
(
error
,
data
)
=>
{
console
.
info
(
"
tunfd:
"
+
JSON
.
stringify
(
data
));
vpn_client
.
startVpn
(
data
,
TunnelFd
)
})
}
catch
(
error
)
{
console
.
info
(
"
vpn setUp fail
"
+
JSON
.
stringify
(
error
));
}
}
fs
.
write
(
tunfd
,
buffer
).
then
(
function
(
number
)
{
}
console
.
info
(
"
write data to file succeed and size is:
"
+
number
);
Destroy
()
{
console
.
info
(
"
vpn Destroy
"
)
vpn_client
.
stopVpn
(
TunnelFd
)
VpnConnection
.
destroy
().
then
(
function
()
{
console
.
info
(
"
vpn Destroy Success
"
)
}).
catch
(
function
(
err
)
{
}).
catch
(
function
(
err
)
{
console
.
info
(
"
write data to file failed with error:
"
+
err
);
console
.
info
(
"
vpn Destroy Failed
"
+
JSON
.
stringify
(
err
))
});
})
}
build
()
{
Row
()
{
Column
()
{
Text
(
this
.
message
)
.
fontSize
(
50
)
.
fontWeight
(
FontWeight
.
Bold
)
.
onClick
(()
=>
{
console
.
info
(
"
vpn Client
"
)
})
Button
(
'
CreateTunnel
'
).
onClick
(()
=>
{
this
.
CreateTunnel
()
}).
fontSize
(
50
)
Button
(
'
Protect
'
).
onClick
(()
=>
{
this
.
Protect
()
}).
fontSize
(
50
)
Button
(
'
SetupVpn
'
).
onClick
(()
=>
{
this
.
SetupVpn
()
}).
fontSize
(
50
)
Button
(
'
Destroy
'
).
onClick
(()
=>
{
this
.
Destroy
()
}).
fontSize
(
50
)
}
.
width
(
'
100%
'
)
}
.
height
(
'
100%
'
)
}
}
})
}
```
### C++ 相关的代码
```
c++
#include "napi/native_api.h"
#include "hilog/log.h"
#include <cstring>
#include <thread>
#include <js_native_api.h>
#include <js_native_api_types.h>
#include <unistd.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <thread>
#include <sys/time.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define BUFFER_SIZE 2048
#define VPN_LOG_TAG "NetMgrVpn"
#define VPN_LOG_DOMAIN 0x15b0
#define MAKE_FILE_NAME (strrchr(__FILE__, '/') + 1)
#define NETMANAGER_VPN_LOGE(fmt, ...) \
OH_LOG_Print(LOG_APP, LOG_ERROR, VPN_LOG_DOMAIN, VPN_LOG_TAG, "vpn [%{public}s %{public}d] " fmt, MAKE_FILE_NAME, \
__LINE__, ##__VA_ARGS__)
#define NETMANAGER_VPN_LOGI(fmt, ...) \
OH_LOG_Print(LOG_APP, LOG_INFO, VPN_LOG_DOMAIN, VPN_LOG_TAG, "vpn [%{public}s %{public}d] " fmt, MAKE_FILE_NAME, \
__LINE__, ##__VA_ARGS__)
#define NETMANAGER_VPN_LOGD(fmt, ...) \
OH_LOG_Print(LOG_APP, LOG_DEBUG, VPN_LOG_DOMAIN, VPN_LOG_TAG, "vpn [%{public}s %{public}d] " fmt, MAKE_FILE_NAME, \
__LINE__, ##__VA_ARGS__)
struct
FdInfo
{
int32_t
tunFd
=
0
;
int32_t
tunnelFd
=
0
;
struct
sockaddr_in
serverAddr
;
};
static
FdInfo
fdInfo
;
static
bool
threadRunF
=
false
;
static
std
::
thread
threadt1
;
static
std
::
thread
threadt2
;
static
constexpr
const
int
MAX_STRING_LENGTH
=
1024
;
std
::
string
GetStringFromValueUtf8
(
napi_env
env
,
napi_value
value
)
{
std
::
string
result
;
char
str
[
MAX_STRING_LENGTH
]
=
{
0
};
size_t
length
=
0
;
napi_get_value_string_utf8
(
env
,
value
,
str
,
MAX_STRING_LENGTH
,
&
length
);
if
(
length
>
0
)
{
return
result
.
append
(
str
,
length
);
}
return
result
;
}
void
HandleReadTunfd
(
FdInfo
fdInfo
)
{
uint8_t
buffer
[
BUFFER_SIZE
]
=
{
0
};
while
(
threadRunF
)
{
int
ret
=
read
(
fdInfo
.
tunFd
,
buffer
,
sizeof
(
buffer
));
if
(
ret
<=
0
)
{
if
(
errno
!=
11
)
{
NETMANAGER_VPN_LOGE
(
"read tun device error: %{public}d, tunfd: %{public}d"
,
errno
,
fdInfo
.
tunFd
);
}
continue
;
}
// 读取到虚拟网卡的数据,通过udp隧道,发送给服务器
NETMANAGER_VPN_LOGD
(
"buffer: %{public}s, len: %{public}d"
,
buffer
,
ret
);
ret
=
sendto
(
fdInfo
.
tunnelFd
,
buffer
,
ret
,
0
,
(
struct
sockaddr
*
)
&
fdInfo
.
serverAddr
,
sizeof
(
fdInfo
.
serverAddr
));
if
(
ret
<=
0
)
{
NETMANAGER_VPN_LOGE
(
"send to server[%{public}s:%{public}d] failed, ret: %{public}d, error: %{public}s"
,
inet_ntoa
(
fdInfo
.
serverAddr
.
sin_addr
),
ntohs
(
fdInfo
.
serverAddr
.
sin_port
),
ret
,
strerror
(
errno
));
continue
;
}
}
}
void
HandleTcpReceived
(
FdInfo
fdInfo
)
{
int
addrlen
=
sizeof
(
struct
sockaddr_in
);
uint8_t
buffer
[
BUFFER_SIZE
]
=
{
0
};
while
(
threadRunF
)
{
int
length
=
recvfrom
(
fdInfo
.
tunnelFd
,
buffer
,
sizeof
(
buffer
),
0
,
(
struct
sockaddr
*
)
&
fdInfo
.
serverAddr
,
(
socklen_t
*
)
&
addrlen
);
if
(
length
<
0
)
{
if
(
errno
!=
11
)
{
NETMANAGER_VPN_LOGE
(
"read tun device error: %{public}d,tunnelfd: %{public}d"
,
errno
,
fdInfo
.
tunnelFd
);
}
continue
;
}
NETMANAGER_VPN_LOGD
(
"from [%{public}s:%{public}d] data: %{public}s, len: %{public}d"
,
inet_ntoa
(
fdInfo
.
serverAddr
.
sin_addr
),
ntohs
(
fdInfo
.
serverAddr
.
sin_port
),
buffer
,
length
);
int
ret
=
write
(
fdInfo
.
tunFd
,
buffer
,
length
);
if
(
ret
<=
0
)
{
NETMANAGER_VPN_LOGE
(
"error Write To Tunfd, errno: %{public}d"
,
errno
);
}
}
}
static
napi_value
TcpConnect
(
napi_env
env
,
napi_callback_info
info
)
{
size_t
argc
=
2
;
napi_value
args
[
2
]
=
{
nullptr
};
napi_get_cb_info
(
env
,
info
,
&
argc
,
args
,
nullptr
,
nullptr
);
int32_t
port
=
0
;
napi_get_value_int32
(
env
,
args
[
1
],
&
port
);
std
::
string
ipAddr
=
GetStringFromValueUtf8
(
env
,
args
[
0
]);
NETMANAGER_VPN_LOGI
(
"ip: %{public}s port: %{public}d"
,
ipAddr
.
c_str
(),
port
);
int32_t
sockFd
=
socket
(
AF_INET
,
SOCK_DGRAM
,
0
);
if
(
sockFd
==
-
1
)
{
NETMANAGER_VPN_LOGE
(
"socket() error"
);
return
0
;
}
struct
timeval
timeout
=
{
1
,
0
};
setsockopt
(
sockFd
,
SOL_SOCKET
,
SO_RCVTIMEO
,
(
char
*
)
&
timeout
,
sizeof
(
struct
timeval
));
memset
(
&
fdInfo
.
serverAddr
,
0
,
sizeof
(
fdInfo
.
serverAddr
));
fdInfo
.
serverAddr
.
sin_family
=
AF_INET
;
fdInfo
.
serverAddr
.
sin_addr
.
s_addr
=
inet_addr
(
ipAddr
.
c_str
());
// server's IP addr
fdInfo
.
serverAddr
.
sin_port
=
htons
(
port
);
// port
NETMANAGER_VPN_LOGI
(
"Connection successful"
);
napi_value
tunnelFd
;
napi_create_int32
(
env
,
sockFd
,
&
tunnelFd
);
return
tunnelFd
;
}
static
napi_value
StartVpn
(
napi_env
env
,
napi_callback_info
info
)
{
size_t
argc
=
2
;
napi_value
args
[
2
]
=
{
nullptr
};
napi_get_cb_info
(
env
,
info
,
&
argc
,
args
,
nullptr
,
nullptr
);
napi_get_value_int32
(
env
,
args
[
0
],
&
fdInfo
.
tunFd
);
napi_get_value_int32
(
env
,
args
[
1
],
&
fdInfo
.
tunnelFd
);
if
(
threadRunF
)
{
threadRunF
=
false
;
threadt1
.
join
();
threadt2
.
join
();
}
threadRunF
=
true
;
std
::
thread
tt1
(
HandleReadTunfd
,
fdInfo
);
std
::
thread
tt2
(
HandleTcpReceived
,
fdInfo
);
threadt1
=
std
::
move
(
tt1
);
threadt2
=
std
::
move
(
tt2
);
NETMANAGER_VPN_LOGI
(
"StartVpn successful"
);
napi_value
retValue
;
napi_create_int32
(
env
,
0
,
&
retValue
);
return
retValue
;
}
static
napi_value
StopVpn
(
napi_env
env
,
napi_callback_info
info
)
{
size_t
argc
=
1
;
napi_value
args
[
1
]
=
{
nullptr
};
napi_get_cb_info
(
env
,
info
,
&
argc
,
args
,
nullptr
,
nullptr
);
int32_t
tunnelFd
;
napi_get_value_int32
(
env
,
args
[
0
],
&
tunnelFd
);
if
(
tunnelFd
)
{
close
(
tunnelFd
);
tunnelFd
=
0
;
}
if
(
threadRunF
)
{
threadRunF
=
false
;
threadt1
.
join
();
threadt2
.
join
();
}
NETMANAGER_VPN_LOGI
(
"StopVpn successful"
);
napi_value
retValue
;
napi_create_int32
(
env
,
0
,
&
retValue
);
return
retValue
;
}
EXTERN_C_START
static
napi_value
Init
(
napi_env
env
,
napi_value
exports
)
{
napi_property_descriptor
desc
[]
=
{
{
"tcpConnect"
,
nullptr
,
TcpConnect
,
nullptr
,
nullptr
,
nullptr
,
napi_default
,
nullptr
},
{
"startVpn"
,
nullptr
,
StartVpn
,
nullptr
,
nullptr
,
nullptr
,
napi_default
,
nullptr
},
{
"stopVpn"
,
nullptr
,
StopVpn
,
nullptr
,
nullptr
,
nullptr
,
napi_default
,
nullptr
},
};
napi_define_properties
(
env
,
exports
,
sizeof
(
desc
)
/
sizeof
(
desc
[
0
]),
desc
);
return
exports
;
}
EXTERN_C_END
static
napi_module
demoModule
=
{
.
nm_version
=
1
,
.
nm_flags
=
0
,
.
nm_filename
=
nullptr
,
.
nm_register_func
=
Init
,
.
nm_modname
=
"entry"
,
.
nm_priv
=
((
void
*
)
0
),
.
reserved
=
{
0
},
};
extern
"C"
__attribute__
((
constructor
))
void
RegisterEntryModule
(
void
)
{
napi_module_register
(
&
demoModule
);
}
```
```
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录