提交 8ac74376 编写于 作者: X xujie

Add Native c++

Change-Id: I85b4755079f3de49536fe8c86bd2d5e630fc3e4d
Signed-off-by: Nxujie <xujie223@huawei.com>
上级 c686ac07
...@@ -26,51 +26,47 @@ VPN即虚拟专网(VPN-Virtual Private Network)在公用网络上建立专 ...@@ -26,51 +26,47 @@ 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;
// 获取VpnConnection对象 let TunnelFd = -1
VpnConnection = vpn.createVpnConnection(context); let VpnConnection = vpn.createVpnConnection(globalThis.context)
console.info("vpn onInit: " + JSON.stringify(VpnConnection));
// 建立TCP 隧道 @Entry
import socket from "@ohos.net.socket"; @Component
var tcp = socket.constructTCPSocketInstance(); struct Index {
tcp.bind({ @State message: string = 'Toy VPN'
address: "0.0.0.0",
family: 1 CreateTunnel() {
}) TunnelFd = vpn_client.tcpConnect("192.168.43.208", 8888)
let connectAddress = { }
address: "192.168.1.11",
port: 8888, Protect() {
family: 1 console.info("vpn Protect")
}; VpnConnection.protect(TunnelFd).then(function () {
tcp.connect({ console.info("vpn Protect Success ")
address: connectAddress, timeout: 6000 }).catch(function (err) {
}) console.info("vpn Protect Failed " + JSON.stringify(err))
tcp.getSocketFd().then((tunnelfd) => {
console.info("tunenlfd: " + tunnelfd);
VpnConnection.protect(tunnelfd, (error, data) => {
console.info(JSON.stringify(error));
console.info(JSON.stringify(data));
}) })
}) }
// 建立 VPN 网络 SetupVpn() {
let config = { console.info("vpn SetupVpn")
let config = {
addresses: [{ addresses: [{
address: { address: {
address: "10.0.0.5", address: "10.0.0.5",
...@@ -80,48 +76,276 @@ let config = { ...@@ -80,48 +76,276 @@ let config = {
}], }],
routes: [], routes: [],
mtu: 1400, mtu: 1400,
dnsAddresses:[ dnsAddresses: [
"114.114.114.114" "114.114.114.114"
], ],
acceptedApplications:[], acceptedApplications: [],
refusedApplications:[] 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));
}
}
Destroy() {
console.info("vpn Destroy")
vpn_client.stopVpn(TunnelFd)
VpnConnection.destroy().then(function () {
console.info("vpn Destroy Success ")
}).catch(function (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%')
}
} }
let tunfd = 0 ```
VpnConnection.setUp(config).then((data) => {
console.info("setUp success, tunfd: " + JSON.stringify(data)) ### C++ 相关的代码
tunfd = data
StartReadFromTun(data) ```c++
}).catch(err => { #include "napi/native_api.h"
console.info("setUp fail" + JSON.stringify(err)) #include "hilog/log.h"
})
#include <cstring>
// 处理虚拟网卡的数据 #include <thread>
import fs from '@ohos.file.fs'; #include <js_native_api.h>
async function StartReadFromTun(tunFd) { #include <js_native_api_types.h>
let buf = new ArrayBuffer(4096); #include <unistd.h>
while (tunFd) { #include <netinet/in.h>
await sleep(1) #include <sys/socket.h>
fs.read(tunFd, buf).then((readLen) => { #include <thread>
console.info("read file data succeed, len: ", readLen); #include <sys/time.h>
await tcp.send({ data: buffer.slice(0, readLen) })
}).catch((err) => { #include <sys/socket.h>
console.info("read file data failed with error message: " + err.message + ", error code: " + err.code); #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;
} }
tcp.on('message', (data) => { void HandleReadTunfd(FdInfo fdInfo) {
console.log("on message:" + JSON.stringify(data.message) + ", remoteInfo:" + JSON.stringify(data.remoteInfo)); uint8_t buffer[BUFFER_SIZE] = {0};
if (data.message) { while (threadRunF) {
if (!tunfd) { int ret = read(fdInfo.tunFd, buffer, sizeof(buffer));
console.info("tunfd is null") if (ret <= 0) {
return; if (errno != 11) {
NETMANAGER_VPN_LOGE("read tun device error: %{public}d, tunfd: %{public}d", errno, fdInfo.tunFd);
} }
fs.write(tunfd, buffer).then(function (number) { continue;
console.info("write data to file succeed and size is:" + number); }
}).catch(function (err) {
console.info("write data to file failed with error:" + err); // 读取到虚拟网卡的数据,通过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.
先完成此消息的编辑!
想要评论请 注册