mirror of
https://github.com/ehang-io/nps.git
synced 2025-07-06 15:37:13 +00:00
Compare commits
No commits in common. "master" and "v0.24.0" have entirely different histories.
163
.github/workflows/release.yml
vendored
163
.github/workflows/release.yml
vendored
@ -1,163 +0,0 @@
|
|||||||
name: Release
|
|
||||||
|
|
||||||
on:
|
|
||||||
release:
|
|
||||||
types: [published]
|
|
||||||
branches: [ master ]
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
|
|
||||||
build_assets:
|
|
||||||
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
|
|
||||||
- name: Set up Go 1.x
|
|
||||||
uses: actions/setup-go@v2
|
|
||||||
with:
|
|
||||||
go-version: 1.15
|
|
||||||
id: go
|
|
||||||
- name: Check out code into the Go module directory
|
|
||||||
uses: actions/checkout@v2
|
|
||||||
- name: Get dependencies
|
|
||||||
run: |
|
|
||||||
go get -v -t -d ./...
|
|
||||||
if [ -f Gopkg.toml ]; then
|
|
||||||
curl https://raw.githubusercontent.com/golang/dep/master/install.sh | sh
|
|
||||||
dep ensure
|
|
||||||
fi
|
|
||||||
- name: Build
|
|
||||||
run: |
|
|
||||||
chmod +x build.assets.sh
|
|
||||||
./build.assets.sh
|
|
||||||
- name: Upload
|
|
||||||
uses: softprops/action-gh-release@v1
|
|
||||||
if: startsWith(github.ref, 'refs/tags/')
|
|
||||||
with:
|
|
||||||
files: |
|
|
||||||
freebsd_386_client.tar.gz
|
|
||||||
freebsd_386_server.tar.gz
|
|
||||||
freebsd_amd64_client.tar.gz
|
|
||||||
freebsd_amd64_server.tar.gz
|
|
||||||
freebsd_arm_client.tar.gz
|
|
||||||
freebsd_arm_server.tar.gz
|
|
||||||
linux_386_client.tar.gz
|
|
||||||
linux_386_server.tar.gz
|
|
||||||
linux_amd64_client.tar.gz
|
|
||||||
linux_amd64_server.tar.gz
|
|
||||||
linux_arm64_client.tar.gz
|
|
||||||
linux_arm64_server.tar.gz
|
|
||||||
linux_arm_v5_client.tar.gz
|
|
||||||
linux_arm_v6_client.tar.gz
|
|
||||||
linux_arm_v7_client.tar.gz
|
|
||||||
linux_arm_v5_server.tar.gz
|
|
||||||
linux_arm_v6_server.tar.gz
|
|
||||||
linux_arm_v7_server.tar.gz
|
|
||||||
linux_mips64le_client.tar.gz
|
|
||||||
linux_mips64le_server.tar.gz
|
|
||||||
linux_mips64_client.tar.gz
|
|
||||||
linux_mips64_server.tar.gz
|
|
||||||
linux_mipsle_client.tar.gz
|
|
||||||
linux_mipsle_server.tar.gz
|
|
||||||
linux_mips_client.tar.gz
|
|
||||||
linux_mips_server.tar.gz
|
|
||||||
darwin_amd64_client.tar.gz
|
|
||||||
darwin_amd64_server.tar.gz
|
|
||||||
windows_386_client.tar.gz
|
|
||||||
windows_386_server.tar.gz
|
|
||||||
windows_amd64_client.tar.gz
|
|
||||||
windows_amd64_server.tar.gz
|
|
||||||
npc_sdk.tar.gz
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
|
|
||||||
build_android:
|
|
||||||
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
|
|
||||||
- name: Check out code into the Go module directory
|
|
||||||
uses: actions/checkout@v2
|
|
||||||
- name: Build
|
|
||||||
run: |
|
|
||||||
chmod +x build.android.sh
|
|
||||||
docker run --rm -i -w /app -v $(pwd):/app -e ANDROID_HOME=/usr/local/android_sdk -e GOPROXY=direct fyneio/fyne-cross:android-latest /app/build.android.sh
|
|
||||||
- name: Upload
|
|
||||||
uses: softprops/action-gh-release@v1
|
|
||||||
if: startsWith(github.ref, 'refs/tags/')
|
|
||||||
with:
|
|
||||||
files: |
|
|
||||||
android_client.apk
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
|
|
||||||
build_spk:
|
|
||||||
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
|
|
||||||
- name: Check out code into the Go module directory
|
|
||||||
uses: actions/checkout@v2
|
|
||||||
- name: Set env
|
|
||||||
run: echo "RELEASE_VERSION=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV
|
|
||||||
- name: Build
|
|
||||||
run: |
|
|
||||||
git clone https://github.com/cnlh/spksrc.git ~/spksrc
|
|
||||||
mkdir ~/spksrc/nps && cp -rf ./* ~/spksrc/nps/
|
|
||||||
docker run -id --name spksrc --env VERSION=${{ env.RELEASE_VERSION }} -e GOPROXY=direct -v ~/spksrc:/spksrc synocommunity/spksrc /bin/bash
|
|
||||||
docker exec spksrc /bin/bash -c 'cd /spksrc && make setup && cd /spksrc/spk/npc && make'
|
|
||||||
cp ~/spksrc/packages/npc_noarch-all_${{ env.RELEASE_VERSION }}-1.spk ./npc_syno.spk
|
|
||||||
- name: Upload
|
|
||||||
uses: softprops/action-gh-release@v1
|
|
||||||
if: startsWith(github.ref, 'refs/tags/')
|
|
||||||
with:
|
|
||||||
files: |
|
|
||||||
npc_syno.spk
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
|
|
||||||
build_docker:
|
|
||||||
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
|
|
||||||
- name: Check out code into the Go module directory
|
|
||||||
uses: actions/checkout@v2
|
|
||||||
- name: Set env
|
|
||||||
run: echo "RELEASE_VERSION=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV
|
|
||||||
- name: Set up QEMU
|
|
||||||
uses: docker/setup-qemu-action@v1
|
|
||||||
- name: Set up Docker Buildx
|
|
||||||
uses: docker/setup-buildx-action@v1
|
|
||||||
- name: Cache Docker layers
|
|
||||||
uses: actions/cache@v2
|
|
||||||
with:
|
|
||||||
path: /tmp/.buildx-cache
|
|
||||||
key: ${{ runner.os }}-buildx-${{ github.sha }}
|
|
||||||
restore-keys: |
|
|
||||||
${{ runner.os }}-buildx-
|
|
||||||
- name: Login to DockerHub
|
|
||||||
uses: docker/login-action@v1
|
|
||||||
with:
|
|
||||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
|
||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
|
||||||
- name: Build and push nps
|
|
||||||
uses: docker/build-push-action@v2
|
|
||||||
with:
|
|
||||||
context: .
|
|
||||||
file: ./Dockerfile.nps
|
|
||||||
platforms: linux/amd64,linux/arm,linux/arm64
|
|
||||||
push: true
|
|
||||||
tags: |
|
|
||||||
${{ secrets.DOCKERHUB_USERNAME }}/nps:latest
|
|
||||||
${{ secrets.DOCKERHUB_USERNAME }}/nps:${{ env.RELEASE_VERSION }}
|
|
||||||
- name: Build and push npc
|
|
||||||
uses: docker/build-push-action@v2
|
|
||||||
with:
|
|
||||||
context: .
|
|
||||||
file: ./Dockerfile.npc
|
|
||||||
platforms: linux/amd64,linux/arm,linux/arm64
|
|
||||||
push: true
|
|
||||||
tags: |
|
|
||||||
${{ secrets.DOCKERHUB_USERNAME }}/npc:latest
|
|
||||||
${{ secrets.DOCKERHUB_USERNAME }}/npc:${{ env.RELEASE_VERSION }}
|
|
57
.travis.yml
57
.travis.yml
@ -1,57 +0,0 @@
|
|||||||
language: go
|
|
||||||
|
|
||||||
go:
|
|
||||||
- 1.14.x
|
|
||||||
services:
|
|
||||||
- docker
|
|
||||||
script:
|
|
||||||
- GOPROXY=direct go test -v ./cmd/nps/
|
|
||||||
os:
|
|
||||||
- linux
|
|
||||||
before_deploy:
|
|
||||||
- chmod +x ./build.sh && chmod +x ./build.android.sh && ./build.sh
|
|
||||||
|
|
||||||
deploy:
|
|
||||||
provider: releases
|
|
||||||
edge: true
|
|
||||||
token: ${GH_TOKEN}
|
|
||||||
cleanup: false
|
|
||||||
file:
|
|
||||||
- freebsd_386_client.tar.gz
|
|
||||||
- freebsd_386_server.tar.gz
|
|
||||||
- freebsd_amd64_client.tar.gz
|
|
||||||
- freebsd_amd64_server.tar.gz
|
|
||||||
- freebsd_arm_client.tar.gz
|
|
||||||
- freebsd_arm_server.tar.gz
|
|
||||||
- linux_386_client.tar.gz
|
|
||||||
- linux_386_server.tar.gz
|
|
||||||
- linux_amd64_client.tar.gz
|
|
||||||
- linux_amd64_server.tar.gz
|
|
||||||
- linux_arm64_client.tar.gz
|
|
||||||
- linux_arm64_server.tar.gz
|
|
||||||
- linux_arm_v5_client.tar.gz
|
|
||||||
- linux_arm_v6_client.tar.gz
|
|
||||||
- linux_arm_v7_client.tar.gz
|
|
||||||
- linux_arm_v5_server.tar.gz
|
|
||||||
- linux_arm_v6_server.tar.gz
|
|
||||||
- linux_arm_v7_server.tar.gz
|
|
||||||
- linux_mips64le_client.tar.gz
|
|
||||||
- linux_mips64le_server.tar.gz
|
|
||||||
- linux_mips64_client.tar.gz
|
|
||||||
- linux_mips64_server.tar.gz
|
|
||||||
- linux_mipsle_client.tar.gz
|
|
||||||
- linux_mipsle_server.tar.gz
|
|
||||||
- linux_mips_client.tar.gz
|
|
||||||
- linux_mips_server.tar.gz
|
|
||||||
- darwin_amd64_client.tar.gz
|
|
||||||
- darwin_amd64_server.tar.gz
|
|
||||||
- windows_386_client.tar.gz
|
|
||||||
- windows_386_server.tar.gz
|
|
||||||
- windows_amd64_client.tar.gz
|
|
||||||
- windows_amd64_server.tar.gz
|
|
||||||
- npc_syno.spk
|
|
||||||
- npc_sdk.tar.gz
|
|
||||||
- android_client.apk
|
|
||||||
on:
|
|
||||||
tags: true
|
|
||||||
all_branches: true
|
|
@ -1,11 +1,10 @@
|
|||||||
FROM golang:1.15 as builder
|
FROM golang as builder
|
||||||
ARG GOPROXY=direct
|
WORKDIR /go/src/github.com/cnlh/nps
|
||||||
WORKDIR /go/src/ehang.io/nps
|
|
||||||
COPY . .
|
COPY . .
|
||||||
RUN go get -d -v ./...
|
RUN go get -d -v ./...
|
||||||
RUN CGO_ENABLED=0 go build -ldflags="-w -s -extldflags -static" ./cmd/npc/npc.go
|
RUN CGO_ENABLED=0 go build -ldflags="-w -s -extldflags -static" ./cmd/npc/npc.go
|
||||||
|
|
||||||
FROM scratch
|
FROM scratch
|
||||||
COPY --from=builder /go/src/ehang.io/nps/npc /
|
COPY --from=builder /go/src/github.com/cnlh/nps/npc /
|
||||||
VOLUME /conf
|
VOLUME /conf
|
||||||
ENTRYPOINT ["/npc"]
|
ENTRYPOINT ["/npc"]
|
||||||
|
@ -1,12 +1,11 @@
|
|||||||
FROM golang:1.15 as builder
|
FROM golang as builder
|
||||||
ARG GOPROXY=direct
|
WORKDIR /go/src/github.com/cnlh/nps
|
||||||
WORKDIR /go/src/ehang.io/nps
|
|
||||||
COPY . .
|
COPY . .
|
||||||
RUN go get -d -v ./...
|
RUN go get -d -v ./...
|
||||||
RUN CGO_ENABLED=0 go build -ldflags="-w -s -extldflags -static" ./cmd/nps/nps.go
|
RUN CGO_ENABLED=0 go build -ldflags="-w -s -extldflags -static" ./cmd/nps/nps.go
|
||||||
|
|
||||||
FROM scratch
|
FROM scratch
|
||||||
COPY --from=builder /go/src/ehang.io/nps/nps /
|
COPY --from=builder /go/src/github.com/cnlh/nps/nps /
|
||||||
COPY --from=builder /go/src/ehang.io/nps/web /web
|
COPY --from=builder /go/src/github.com/cnlh/nps/web /web
|
||||||
VOLUME /conf
|
VOLUME /conf
|
||||||
CMD ["/nps"]
|
CMD ["/nps"]
|
||||||
|
90
README_zh.md
90
README_zh.md
@ -1,90 +0,0 @@
|
|||||||
|
|
||||||
# nps
|
|
||||||
 
|
|
||||||
[](https://gitter.im/cnlh-nps/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
|
|
||||||

|
|
||||||

|
|
||||||
|
|
||||||
[README](https://github.com/ehang-io/nps/blob/master/README.md)|[中文文档](https://github.com/ehang-io/nps/blob/master/README_zh.md)
|
|
||||||
|
|
||||||
nps是一款轻量级、高性能、功能强大的**内网穿透**代理服务器。目前支持**tcp、udp流量转发**,可支持任何**tcp、udp**上层协议(访问内网网站、本地支付接口调试、ssh访问、远程桌面,内网dns解析等等……),此外还**支持内网http代理、内网socks5代理**、**p2p等**,并带有功能强大的web管理端。
|
|
||||||
|
|
||||||
|
|
||||||
## 背景
|
|
||||||

|
|
||||||
|
|
||||||
1. 做微信公众号开发、小程序开发等----> 域名代理模式
|
|
||||||
|
|
||||||
2. 想在外网通过ssh连接内网的机器,做云服务器到内网服务器端口的映射,----> tcp代理模式
|
|
||||||
|
|
||||||
3. 在非内网环境下使用内网dns,或者需要通过udp访问内网机器等----> udp代理模式
|
|
||||||
|
|
||||||
4. 在外网使用HTTP代理访问内网站点----> http代理模式
|
|
||||||
|
|
||||||
5. 搭建一个内网穿透ss,在外网如同使用内网vpn一样访问内网资源或者设备----> socks5代理模式
|
|
||||||
## 特点
|
|
||||||
- 协议支持全面,兼容几乎所有常用协议,例如tcp、udp、http(s)、socks5、p2p、http代理...
|
|
||||||
- 全平台兼容(linux、windows、macos、群辉等),支持一键安装为系统服务
|
|
||||||
- 控制全面,同时支持服务端和客户端控制
|
|
||||||
- https集成,支持将后端代理和web服务转成https,同时支持多证书
|
|
||||||
- 操作简单,只需简单的配置即可在web ui上完成其余操作
|
|
||||||
- 展示信息全面,流量、系统信息、即时带宽、客户端版本等
|
|
||||||
- 扩展功能强大,该有的都有了(缓存、压缩、加密、流量限制、带宽限制、端口复用等等)
|
|
||||||
- 域名解析具备自定义header、404页面配置、host修改、站点保护、URL路由、泛解析等功能
|
|
||||||
- 服务端支持多用户和用户注册功能
|
|
||||||
|
|
||||||
**没找到你想要的功能?不要紧,点击[进入文档](https://ehang-io.github.io/nps)查找吧**
|
|
||||||
## 快速开始
|
|
||||||
|
|
||||||
### 安装
|
|
||||||
> [releases](https://github.com/ehang-io/nps/releases)
|
|
||||||
|
|
||||||
下载对应的系统版本即可,服务端和客户端是单独的
|
|
||||||
|
|
||||||
### 服务端启动
|
|
||||||
下载完服务器压缩包后,解压,然后进入解压后的文件夹
|
|
||||||
|
|
||||||
- 执行安装命令
|
|
||||||
|
|
||||||
对于linux|darwin ```sudo ./nps install```
|
|
||||||
|
|
||||||
对于windows,管理员身份运行cmd,进入安装目录 ```nps.exe install```
|
|
||||||
|
|
||||||
- 默认端口
|
|
||||||
|
|
||||||
nps默认配置文件使用了80,443,8080,8024端口
|
|
||||||
|
|
||||||
80与443端口为域名解析模式默认端口
|
|
||||||
|
|
||||||
8080为web管理访问端口
|
|
||||||
|
|
||||||
8024为网桥端口,用于客户端与服务器通信
|
|
||||||
|
|
||||||
- 启动
|
|
||||||
|
|
||||||
对于linux|darwin ```sudo nps start```
|
|
||||||
|
|
||||||
对于windows,管理员身份运行cmd,进入程序目录 ```nps.exe start```
|
|
||||||
|
|
||||||
```安装后windows配置文件位于 C:\Program Files\nps,linux和darwin位于/etc/nps```
|
|
||||||
|
|
||||||
**如果发现没有启动成功,可以查看日志(Windows日志文件位于当前运行目录下,linux和darwin位于/var/log/nps.log)**
|
|
||||||
- 访问服务端ip:web服务端口(默认为8080)
|
|
||||||
- 使用用户名和密码登陆(默认admin/123,正式使用一定要更改)
|
|
||||||
- 创建客户端
|
|
||||||
|
|
||||||
### 客户端连接
|
|
||||||
- 点击web管理中客户端前的+号,复制启动命令
|
|
||||||
- 执行启动命令,linux直接执行即可,windows将./npc换成npc.exe用cmd执行
|
|
||||||
|
|
||||||
如果需要注册到系统服务可查看[注册到系统服务](https://ehang-io.github.io/nps/#/use?id=注册到系统服务)
|
|
||||||
|
|
||||||
### 配置
|
|
||||||
- 客户端连接后,在web中配置对应穿透服务即可
|
|
||||||
- 更多高级用法见[完整文档](https://ehang-io.github.io/nps/)
|
|
||||||
|
|
||||||
## 贡献
|
|
||||||
- 如果遇到bug可以直接提交至dev分支
|
|
||||||
- 使用遇到问题可以通过issues反馈
|
|
||||||
- 项目处于开发阶段,还有很多待完善的地方,如果可以贡献代码,请提交 PR 至 dev 分支
|
|
||||||
- 如果有新的功能特性反馈,可以通过issues或者qq群反馈
|
|
110
bridge/bridge.go
110
bridge/bridge.go
@ -1,7 +1,6 @@
|
|||||||
package bridge
|
package bridge
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"ehang.io/nps-mux"
|
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
@ -12,59 +11,56 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"ehang.io/nps/lib/common"
|
|
||||||
"ehang.io/nps/lib/conn"
|
|
||||||
"ehang.io/nps/lib/crypt"
|
|
||||||
"ehang.io/nps/lib/file"
|
|
||||||
"ehang.io/nps/lib/version"
|
|
||||||
"ehang.io/nps/server/connection"
|
|
||||||
"ehang.io/nps/server/tool"
|
|
||||||
"github.com/astaxie/beego"
|
"github.com/astaxie/beego"
|
||||||
"github.com/astaxie/beego/logs"
|
"github.com/astaxie/beego/logs"
|
||||||
|
"github.com/cnlh/nps/lib/common"
|
||||||
|
"github.com/cnlh/nps/lib/conn"
|
||||||
|
"github.com/cnlh/nps/lib/crypt"
|
||||||
|
"github.com/cnlh/nps/lib/file"
|
||||||
|
"github.com/cnlh/nps/lib/mux"
|
||||||
|
"github.com/cnlh/nps/lib/version"
|
||||||
|
"github.com/cnlh/nps/server/connection"
|
||||||
|
"github.com/cnlh/nps/server/tool"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Client struct {
|
type Client struct {
|
||||||
tunnel *nps_mux.Mux
|
tunnel *mux.Mux
|
||||||
signal *conn.Conn
|
signal *conn.Conn
|
||||||
file *nps_mux.Mux
|
file *mux.Mux
|
||||||
Version string
|
|
||||||
retryTime int // it will be add 1 when ping not ok until to 3 will close the client
|
retryTime int // it will be add 1 when ping not ok until to 3 will close the client
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewClient(t, f *nps_mux.Mux, s *conn.Conn, vs string) *Client {
|
func NewClient(t, f *mux.Mux, s *conn.Conn) *Client {
|
||||||
return &Client{
|
return &Client{
|
||||||
signal: s,
|
signal: s,
|
||||||
tunnel: t,
|
tunnel: t,
|
||||||
file: f,
|
file: f,
|
||||||
Version: vs,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type Bridge struct {
|
type Bridge struct {
|
||||||
TunnelPort int //通信隧道端口
|
TunnelPort int //通信隧道端口
|
||||||
Client sync.Map
|
Client sync.Map
|
||||||
Register sync.Map
|
Register sync.Map
|
||||||
tunnelType string //bridge type kcp or tcp
|
tunnelType string //bridge type kcp or tcp
|
||||||
OpenTask chan *file.Tunnel
|
OpenTask chan *file.Tunnel
|
||||||
CloseTask chan *file.Tunnel
|
CloseTask chan *file.Tunnel
|
||||||
CloseClient chan int
|
CloseClient chan int
|
||||||
SecretChan chan *conn.Secret
|
SecretChan chan *conn.Secret
|
||||||
ipVerify bool
|
ipVerify bool
|
||||||
runList sync.Map //map[int]interface{}
|
runList map[int]interface{}
|
||||||
disconnectTime int
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewTunnel(tunnelPort int, tunnelType string, ipVerify bool, runList sync.Map, disconnectTime int) *Bridge {
|
func NewTunnel(tunnelPort int, tunnelType string, ipVerify bool, runList map[int]interface{}) *Bridge {
|
||||||
return &Bridge{
|
return &Bridge{
|
||||||
TunnelPort: tunnelPort,
|
TunnelPort: tunnelPort,
|
||||||
tunnelType: tunnelType,
|
tunnelType: tunnelType,
|
||||||
OpenTask: make(chan *file.Tunnel),
|
OpenTask: make(chan *file.Tunnel),
|
||||||
CloseTask: make(chan *file.Tunnel),
|
CloseTask: make(chan *file.Tunnel),
|
||||||
CloseClient: make(chan int),
|
CloseClient: make(chan int),
|
||||||
SecretChan: make(chan *conn.Secret),
|
SecretChan: make(chan *conn.Secret),
|
||||||
ipVerify: ipVerify,
|
ipVerify: ipVerify,
|
||||||
runList: runList,
|
runList: runList,
|
||||||
disconnectTime: disconnectTime,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -170,23 +166,16 @@ func (s *Bridge) cliProcess(c *conn.Conn) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
//version check
|
//version check
|
||||||
if b, err := c.GetShortLenContent(); err != nil || string(b) != version.GetVersion() {
|
if b, err := c.GetShortContent(32); err != nil || string(b) != crypt.Md5(version.GetVersion()) {
|
||||||
logs.Info("The client %s version does not match", c.Conn.RemoteAddr())
|
logs.Info("The client %s version does not match", c.Conn.RemoteAddr())
|
||||||
c.Close()
|
c.Close()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
//version get
|
|
||||||
var vs []byte
|
|
||||||
var err error
|
|
||||||
if vs, err = c.GetShortLenContent(); err != nil {
|
|
||||||
logs.Info("get client %s version error", err.Error())
|
|
||||||
c.Close()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
//write server version to client
|
//write server version to client
|
||||||
c.Write([]byte(crypt.Md5(version.GetVersion())))
|
c.Write([]byte(crypt.Md5(version.GetVersion())))
|
||||||
c.SetReadDeadlineBySecond(5)
|
c.SetReadDeadlineBySecond(5)
|
||||||
var buf []byte
|
var buf []byte
|
||||||
|
var err error
|
||||||
//get vKey from client
|
//get vKey from client
|
||||||
if buf, err = c.GetShortContent(32); err != nil {
|
if buf, err = c.GetShortContent(32); err != nil {
|
||||||
c.Close()
|
c.Close()
|
||||||
@ -202,7 +191,7 @@ func (s *Bridge) cliProcess(c *conn.Conn) {
|
|||||||
s.verifySuccess(c)
|
s.verifySuccess(c)
|
||||||
}
|
}
|
||||||
if flag, err := c.ReadFlag(); err == nil {
|
if flag, err := c.ReadFlag(); err == nil {
|
||||||
s.typeDeal(flag, c, id, string(vs))
|
s.typeDeal(flag, c, id)
|
||||||
} else {
|
} else {
|
||||||
logs.Warn(err, flag)
|
logs.Warn(err, flag)
|
||||||
}
|
}
|
||||||
@ -225,7 +214,7 @@ func (s *Bridge) DelClient(id int) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//use different
|
//use different
|
||||||
func (s *Bridge) typeDeal(typeVal string, c *conn.Conn, id int, vs string) {
|
func (s *Bridge) typeDeal(typeVal string, c *conn.Conn, id int) {
|
||||||
isPub := file.GetDb().IsPubClient(id)
|
isPub := file.GetDb().IsPubClient(id)
|
||||||
switch typeVal {
|
switch typeVal {
|
||||||
case common.WORK_MAIN:
|
case common.WORK_MAIN:
|
||||||
@ -233,25 +222,18 @@ func (s *Bridge) typeDeal(typeVal string, c *conn.Conn, id int, vs string) {
|
|||||||
c.Close()
|
c.Close()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
tcpConn, ok := c.Conn.(*net.TCPConn)
|
|
||||||
if ok {
|
|
||||||
// add tcp keep alive option for signal connection
|
|
||||||
_ = tcpConn.SetKeepAlive(true)
|
|
||||||
_ = tcpConn.SetKeepAlivePeriod(5 * time.Second)
|
|
||||||
}
|
|
||||||
//the vKey connect by another ,close the client of before
|
//the vKey connect by another ,close the client of before
|
||||||
if v, ok := s.Client.LoadOrStore(id, NewClient(nil, nil, c, vs)); ok {
|
if v, ok := s.Client.LoadOrStore(id, NewClient(nil, nil, c)); ok {
|
||||||
if v.(*Client).signal != nil {
|
if v.(*Client).signal != nil {
|
||||||
v.(*Client).signal.WriteClose()
|
v.(*Client).signal.WriteClose()
|
||||||
}
|
}
|
||||||
v.(*Client).signal = c
|
v.(*Client).signal = c
|
||||||
v.(*Client).Version = vs
|
|
||||||
}
|
}
|
||||||
go s.GetHealthFromClient(id, c)
|
go s.GetHealthFromClient(id, c)
|
||||||
logs.Info("clientId %d connection succeeded, address:%s ", id, c.Conn.RemoteAddr())
|
logs.Info("clientId %d connection succeeded, address:%s ", id, c.Conn.RemoteAddr())
|
||||||
case common.WORK_CHAN:
|
case common.WORK_CHAN:
|
||||||
muxConn := nps_mux.NewMux(c.Conn, s.tunnelType, s.disconnectTime)
|
muxConn := mux.NewMux(c.Conn, s.tunnelType)
|
||||||
if v, ok := s.Client.LoadOrStore(id, NewClient(muxConn, nil, nil, vs)); ok {
|
if v, ok := s.Client.LoadOrStore(id, NewClient(muxConn, nil, nil)); ok {
|
||||||
v.(*Client).tunnel = muxConn
|
v.(*Client).tunnel = muxConn
|
||||||
}
|
}
|
||||||
case common.WORK_CONFIG:
|
case common.WORK_CONFIG:
|
||||||
@ -271,8 +253,8 @@ func (s *Bridge) typeDeal(typeVal string, c *conn.Conn, id int, vs string) {
|
|||||||
logs.Error("secret error, failed to match the key successfully")
|
logs.Error("secret error, failed to match the key successfully")
|
||||||
}
|
}
|
||||||
case common.WORK_FILE:
|
case common.WORK_FILE:
|
||||||
muxConn := nps_mux.NewMux(c.Conn, s.tunnelType, s.disconnectTime)
|
muxConn := mux.NewMux(c.Conn, s.tunnelType)
|
||||||
if v, ok := s.Client.LoadOrStore(id, NewClient(nil, muxConn, nil, vs)); ok {
|
if v, ok := s.Client.LoadOrStore(id, NewClient(nil, muxConn, nil)); ok {
|
||||||
v.(*Client).file = muxConn
|
v.(*Client).file = muxConn
|
||||||
}
|
}
|
||||||
case common.WORK_P2P:
|
case common.WORK_P2P:
|
||||||
@ -329,7 +311,7 @@ func (s *Bridge) SendLinkInfo(clientId int, link *conn.Link, t *file.Tunnel) (ta
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var tunnel *nps_mux.Mux
|
var tunnel *mux.Mux
|
||||||
if t != nil && t.Mode == "file" {
|
if t != nil && t.Mode == "file" {
|
||||||
tunnel = v.(*Client).file
|
tunnel = v.(*Client).file
|
||||||
} else {
|
} else {
|
||||||
@ -360,7 +342,6 @@ func (s *Bridge) SendLinkInfo(clientId int, link *conn.Link, t *file.Tunnel) (ta
|
|||||||
|
|
||||||
func (s *Bridge) ping() {
|
func (s *Bridge) ping() {
|
||||||
ticker := time.NewTicker(time.Second * 5)
|
ticker := time.NewTicker(time.Second * 5)
|
||||||
defer ticker.Stop()
|
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-ticker.C:
|
case <-ticker.C:
|
||||||
@ -415,8 +396,7 @@ loop:
|
|||||||
})
|
})
|
||||||
file.GetDb().JsonDb.Tasks.Range(func(key, value interface{}) bool {
|
file.GetDb().JsonDb.Tasks.Range(func(key, value interface{}) bool {
|
||||||
v := value.(*file.Tunnel)
|
v := value.(*file.Tunnel)
|
||||||
//if _, ok := s.runList[v.Id]; ok && v.Client.Id == id {
|
if _, ok := s.runList[v.Id]; ok && v.Client.Id == id {
|
||||||
if _, ok := s.runList.Load(v.Id); ok && v.Client.Id == id {
|
|
||||||
str += v.Remark + common.CONN_DATA_SEQ
|
str += v.Remark + common.CONN_DATA_SEQ
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
@ -438,7 +418,7 @@ loop:
|
|||||||
}
|
}
|
||||||
c.WriteAddOk()
|
c.WriteAddOk()
|
||||||
c.Write([]byte(client.VerifyKey))
|
c.Write([]byte(client.VerifyKey))
|
||||||
s.Client.Store(client.Id, NewClient(nil, nil, nil, ""))
|
s.Client.Store(client.Id, NewClient(nil, nil, nil))
|
||||||
}
|
}
|
||||||
case common.NEW_HOST:
|
case common.NEW_HOST:
|
||||||
h, err := c.GetHostInfo()
|
h, err := c.GetHostInfo()
|
||||||
|
@ -1,34 +0,0 @@
|
|||||||
#/bin/bash
|
|
||||||
|
|
||||||
cd /go
|
|
||||||
apt-get install libegl1-mesa-dev libgles2-mesa-dev libx11-dev xorg-dev -y
|
|
||||||
go get -u fyne.io/fyne/v2/cmd/fyne fyne.io/fyne/v2
|
|
||||||
#mkdir -p /go/src/fyne.io
|
|
||||||
#cd src/fyne.io
|
|
||||||
#git clone https://github.com/fyne-io/fyne.git
|
|
||||||
#cd fyne
|
|
||||||
#git checkout v1.2.0
|
|
||||||
#go install -v ./cmd/fyne
|
|
||||||
#fyne package -os android fyne.io/fyne/cmd/hello
|
|
||||||
echo "fyne install success"
|
|
||||||
mkdir -p /go/src/ehang.io/nps
|
|
||||||
cp -R /app/* /go/src/ehang.io/nps
|
|
||||||
cd /go/src/ehang.io/nps
|
|
||||||
#go get -u fyne.io/fyne fyne.io/fyne/cmd/fyne
|
|
||||||
rm cmd/npc/sdk.go
|
|
||||||
#go get -u ./...
|
|
||||||
#go mod tidy
|
|
||||||
#rm -rf /go/src/golang.org/x/mobile
|
|
||||||
echo "tidy success"
|
|
||||||
cd /go/src/ehang.io/nps
|
|
||||||
go mod vendor
|
|
||||||
cd vendor
|
|
||||||
cp -R * /go/src
|
|
||||||
cd ..
|
|
||||||
rm -rf vendor
|
|
||||||
#rm -rf ~/.cache/*
|
|
||||||
echo "vendor success"
|
|
||||||
cd gui/npc
|
|
||||||
fyne package -appID org.nps.client -os android -icon ../../docs/logo.png
|
|
||||||
mv npc.apk /app/android_client.apk
|
|
||||||
echo "android build success"
|
|
156
build.assets.sh
156
build.assets.sh
@ -1,156 +0,0 @@
|
|||||||
export GOPROXY=direct
|
|
||||||
|
|
||||||
sudo apt-get update
|
|
||||||
sudo apt-get install gcc-mingw-w64-i686 gcc-multilib
|
|
||||||
env GOOS=windows GOARCH=386 CGO_ENABLED=1 CC=i686-w64-mingw32-gcc go build -ldflags "-s -w -extldflags -static -extldflags -static" -buildmode=c-shared -o npc_sdk.dll cmd/npc/sdk.go
|
|
||||||
env GOOS=linux GOARCH=386 CGO_ENABLED=1 CC=gcc go build -ldflags "-s -w -extldflags -static -extldflags -static" -buildmode=c-shared -o npc_sdk.so cmd/npc/sdk.go
|
|
||||||
tar -czvf npc_sdk.tar.gz npc_sdk.dll npc_sdk.so npc_sdk.h
|
|
||||||
|
|
||||||
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go
|
|
||||||
|
|
||||||
tar -czvf linux_amd64_client.tar.gz npc conf/npc.conf conf/multi_account.conf
|
|
||||||
|
|
||||||
CGO_ENABLED=0 GOOS=linux GOARCH=386 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go
|
|
||||||
|
|
||||||
tar -czvf linux_386_client.tar.gz npc conf/npc.conf conf/multi_account.conf
|
|
||||||
|
|
||||||
CGO_ENABLED=0 GOOS=freebsd GOARCH=386 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go
|
|
||||||
|
|
||||||
tar -czvf freebsd_386_client.tar.gz npc conf/npc.conf conf/multi_account.conf
|
|
||||||
|
|
||||||
CGO_ENABLED=0 GOOS=freebsd GOARCH=amd64 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go
|
|
||||||
|
|
||||||
tar -czvf freebsd_amd64_client.tar.gz npc conf/npc.conf conf/multi_account.conf
|
|
||||||
|
|
||||||
CGO_ENABLED=0 GOOS=freebsd GOARCH=arm go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go
|
|
||||||
|
|
||||||
tar -czvf freebsd_arm_client.tar.gz npc conf/npc.conf conf/multi_account.conf
|
|
||||||
|
|
||||||
CGO_ENABLED=0 GOOS=linux GOARCH=arm GOARM=7 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go
|
|
||||||
|
|
||||||
tar -czvf linux_arm_v7_client.tar.gz npc conf/npc.conf conf/multi_account.conf
|
|
||||||
|
|
||||||
CGO_ENABLED=0 GOOS=linux GOARCH=arm GOARM=6 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go
|
|
||||||
|
|
||||||
tar -czvf linux_arm_v6_client.tar.gz npc conf/npc.conf conf/multi_account.conf
|
|
||||||
|
|
||||||
CGO_ENABLED=0 GOOS=linux GOARCH=arm GOARM=5 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go
|
|
||||||
|
|
||||||
tar -czvf linux_arm_v5_client.tar.gz npc conf/npc.conf conf/multi_account.conf
|
|
||||||
|
|
||||||
|
|
||||||
CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go
|
|
||||||
|
|
||||||
tar -czvf linux_arm64_client.tar.gz npc conf/npc.conf conf/multi_account.conf
|
|
||||||
|
|
||||||
|
|
||||||
CGO_ENABLED=0 GOOS=linux GOARCH=mips64 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go
|
|
||||||
|
|
||||||
tar -czvf linux_mips64_client.tar.gz npc conf/npc.conf conf/multi_account.conf
|
|
||||||
|
|
||||||
|
|
||||||
CGO_ENABLED=0 GOOS=linux GOARCH=mips64le go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go
|
|
||||||
|
|
||||||
tar -czvf linux_mips64le_client.tar.gz npc conf/npc.conf conf/multi_account.conf
|
|
||||||
|
|
||||||
|
|
||||||
CGO_ENABLED=0 GOOS=linux GOARCH=mipsle go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go
|
|
||||||
|
|
||||||
tar -czvf linux_mipsle_client.tar.gz npc conf/npc.conf conf/multi_account.conf
|
|
||||||
|
|
||||||
|
|
||||||
CGO_ENABLED=0 GOOS=linux GOARCH=mips go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go
|
|
||||||
|
|
||||||
tar -czvf linux_mips_client.tar.gz npc conf/npc.conf conf/multi_account.conf
|
|
||||||
|
|
||||||
|
|
||||||
CGO_ENABLED=0 GOOS=windows GOARCH=386 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go
|
|
||||||
|
|
||||||
tar -czvf windows_386_client.tar.gz npc.exe conf/npc.conf conf/multi_account.conf
|
|
||||||
|
|
||||||
|
|
||||||
CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go
|
|
||||||
|
|
||||||
tar -czvf windows_amd64_client.tar.gz npc.exe conf/npc.conf conf/multi_account.conf
|
|
||||||
|
|
||||||
|
|
||||||
CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go
|
|
||||||
|
|
||||||
tar -czvf darwin_amd64_client.tar.gz npc conf/npc.conf conf/multi_account.conf
|
|
||||||
|
|
||||||
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go
|
|
||||||
|
|
||||||
tar -czvf linux_amd64_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key conf/server.pem web/views web/static nps
|
|
||||||
|
|
||||||
CGO_ENABLED=0 GOOS=linux GOARCH=386 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go
|
|
||||||
|
|
||||||
tar -czvf linux_386_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key conf/server.pem web/views web/static nps
|
|
||||||
|
|
||||||
CGO_ENABLED=0 GOOS=linux GOARCH=arm GOARM=5 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go
|
|
||||||
|
|
||||||
tar -czvf linux_arm_v5_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key conf/server.pem web/views web/static nps
|
|
||||||
|
|
||||||
CGO_ENABLED=0 GOOS=linux GOARCH=arm GOARM=6 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go
|
|
||||||
|
|
||||||
tar -czvf linux_arm_v6_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key conf/server.pem web/views web/static nps
|
|
||||||
|
|
||||||
CGO_ENABLED=0 GOOS=linux GOARCH=arm GOARM=7 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go
|
|
||||||
|
|
||||||
tar -czvf linux_arm_v7_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key conf/server.pem web/views web/static nps
|
|
||||||
|
|
||||||
|
|
||||||
CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go
|
|
||||||
|
|
||||||
tar -czvf linux_arm64_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key conf/server.pem web/views web/static nps
|
|
||||||
|
|
||||||
|
|
||||||
CGO_ENABLED=0 GOOS=freebsd GOARCH=arm go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go
|
|
||||||
|
|
||||||
tar -czvf freebsd_arm_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key conf/server.pem web/views web/static nps
|
|
||||||
|
|
||||||
|
|
||||||
CGO_ENABLED=0 GOOS=freebsd GOARCH=386 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go
|
|
||||||
|
|
||||||
tar -czvf freebsd_386_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key conf/server.pem web/views web/static nps
|
|
||||||
|
|
||||||
|
|
||||||
CGO_ENABLED=0 GOOS=freebsd GOARCH=amd64 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go
|
|
||||||
|
|
||||||
tar -czvf freebsd_amd64_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key conf/server.pem web/views web/static nps
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
CGO_ENABLED=0 GOOS=linux GOARCH=mips go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go
|
|
||||||
|
|
||||||
tar -czvf linux_mips_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key conf/server.pem web/views web/static nps
|
|
||||||
|
|
||||||
|
|
||||||
CGO_ENABLED=0 GOOS=linux GOARCH=mips64 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go
|
|
||||||
|
|
||||||
tar -czvf linux_mips64_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key conf/server.pem web/views web/static nps
|
|
||||||
|
|
||||||
|
|
||||||
CGO_ENABLED=0 GOOS=linux GOARCH=mips64le go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go
|
|
||||||
|
|
||||||
tar -czvf linux_mips64le_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key conf/server.pem web/views web/static nps
|
|
||||||
|
|
||||||
|
|
||||||
CGO_ENABLED=0 GOOS=linux GOARCH=mipsle go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go
|
|
||||||
|
|
||||||
tar -czvf linux_mipsle_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key conf/server.pem web/views web/static nps
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go
|
|
||||||
|
|
||||||
tar -czvf darwin_amd64_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key conf/server.pem web/views web/static nps
|
|
||||||
|
|
||||||
|
|
||||||
CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go
|
|
||||||
|
|
||||||
tar -czvf windows_amd64_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key conf/server.pem web/views web/static nps.exe
|
|
||||||
|
|
||||||
|
|
||||||
CGO_ENABLED=0 GOOS=windows GOARCH=386 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go
|
|
||||||
|
|
||||||
tar -czvf windows_386_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key conf/server.pem web/views web/static nps.exe
|
|
168
build.sh
168
build.sh
@ -1,168 +0,0 @@
|
|||||||
#/bash/sh
|
|
||||||
export VERSION=0.26.10
|
|
||||||
export GOPROXY=direct
|
|
||||||
|
|
||||||
sudo apt-get update
|
|
||||||
sudo apt-get install gcc-mingw-w64-i686 gcc-multilib
|
|
||||||
env GOOS=windows GOARCH=386 CGO_ENABLED=1 CC=i686-w64-mingw32-gcc go build -ldflags "-s -w -extldflags -static -extldflags -static" -buildmode=c-shared -o npc_sdk.dll cmd/npc/sdk.go
|
|
||||||
env GOOS=linux GOARCH=386 CGO_ENABLED=1 CC=gcc go build -ldflags "-s -w -extldflags -static -extldflags -static" -buildmode=c-shared -o npc_sdk.so cmd/npc/sdk.go
|
|
||||||
tar -czvf npc_sdk.tar.gz npc_sdk.dll npc_sdk.so npc_sdk.h
|
|
||||||
|
|
||||||
wget https://github.com/upx/upx/releases/download/v3.95/upx-3.95-amd64_linux.tar.xz
|
|
||||||
tar -xvf upx-3.95-amd64_linux.tar.xz
|
|
||||||
cp upx-3.95-amd64_linux/upx ./
|
|
||||||
|
|
||||||
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go
|
|
||||||
tar -czvf linux_amd64_client.tar.gz npc conf/npc.conf conf/multi_account.conf
|
|
||||||
|
|
||||||
|
|
||||||
CGO_ENABLED=0 GOOS=linux GOARCH=386 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go
|
|
||||||
tar -czvf linux_386_client.tar.gz npc conf/npc.conf conf/multi_account.conf
|
|
||||||
|
|
||||||
|
|
||||||
CGO_ENABLED=0 GOOS=freebsd GOARCH=386 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go
|
|
||||||
tar -czvf freebsd_386_client.tar.gz npc conf/npc.conf conf/multi_account.conf
|
|
||||||
|
|
||||||
|
|
||||||
CGO_ENABLED=0 GOOS=freebsd GOARCH=amd64 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go
|
|
||||||
tar -czvf freebsd_amd64_client.tar.gz npc conf/npc.conf conf/multi_account.conf
|
|
||||||
|
|
||||||
|
|
||||||
CGO_ENABLED=0 GOOS=freebsd GOARCH=arm go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go
|
|
||||||
tar -czvf freebsd_arm_client.tar.gz npc conf/npc.conf conf/multi_account.conf
|
|
||||||
|
|
||||||
|
|
||||||
CGO_ENABLED=0 GOOS=linux GOARCH=arm GOARM=7 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go
|
|
||||||
tar -czvf linux_arm_v7_client.tar.gz npc conf/npc.conf conf/multi_account.conf
|
|
||||||
|
|
||||||
|
|
||||||
CGO_ENABLED=0 GOOS=linux GOARCH=arm GOARM=6 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go
|
|
||||||
tar -czvf linux_arm_v6_client.tar.gz npc conf/npc.conf conf/multi_account.conf
|
|
||||||
|
|
||||||
|
|
||||||
CGO_ENABLED=0 GOOS=linux GOARCH=arm GOARM=5 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go
|
|
||||||
tar -czvf linux_arm_v5_client.tar.gz npc conf/npc.conf conf/multi_account.conf
|
|
||||||
|
|
||||||
|
|
||||||
CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go
|
|
||||||
tar -czvf linux_arm64_client.tar.gz npc conf/npc.conf conf/multi_account.conf
|
|
||||||
|
|
||||||
|
|
||||||
CGO_ENABLED=0 GOOS=linux GOARCH=mips64 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go
|
|
||||||
tar -czvf linux_mips64_client.tar.gz npc conf/npc.conf conf/multi_account.conf
|
|
||||||
|
|
||||||
|
|
||||||
CGO_ENABLED=0 GOOS=linux GOARCH=mips64le go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go
|
|
||||||
tar -czvf linux_mips64le_client.tar.gz npc conf/npc.conf conf/multi_account.conf
|
|
||||||
|
|
||||||
|
|
||||||
CGO_ENABLED=0 GOOS=linux GOARCH=mipsle go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go
|
|
||||||
tar -czvf linux_mipsle_client.tar.gz npc conf/npc.conf conf/multi_account.conf
|
|
||||||
|
|
||||||
|
|
||||||
CGO_ENABLED=0 GOOS=linux GOARCH=mips go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go
|
|
||||||
tar -czvf linux_mips_client.tar.gz npc conf/npc.conf conf/multi_account.conf
|
|
||||||
|
|
||||||
|
|
||||||
CGO_ENABLED=0 GOOS=windows GOARCH=386 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go
|
|
||||||
tar -czvf windows_386_client.tar.gz npc.exe conf/npc.conf conf/multi_account.conf
|
|
||||||
|
|
||||||
|
|
||||||
CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go
|
|
||||||
tar -czvf windows_amd64_client.tar.gz npc.exe conf/npc.conf conf/multi_account.conf
|
|
||||||
|
|
||||||
|
|
||||||
CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go
|
|
||||||
tar -czvf darwin_amd64_client.tar.gz npc conf/npc.conf conf/multi_account.conf
|
|
||||||
|
|
||||||
|
|
||||||
CGO_ENABLED=0 GOOS=darwin GOARCH=arm64 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go
|
|
||||||
tar -czvf darwin_arm64_client.tar.gz npc conf/npc.conf conf/multi_account.conf
|
|
||||||
|
|
||||||
|
|
||||||
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go
|
|
||||||
tar -czvf linux_amd64_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key conf/server.pem web/views web/static nps
|
|
||||||
|
|
||||||
|
|
||||||
CGO_ENABLED=0 GOOS=linux GOARCH=386 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go
|
|
||||||
tar -czvf linux_386_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key conf/server.pem web/views web/static nps
|
|
||||||
|
|
||||||
|
|
||||||
CGO_ENABLED=0 GOOS=linux GOARCH=arm GOARM=5 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go
|
|
||||||
tar -czvf linux_arm_v5_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key conf/server.pem web/views web/static nps
|
|
||||||
|
|
||||||
|
|
||||||
CGO_ENABLED=0 GOOS=linux GOARCH=arm GOARM=6 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go
|
|
||||||
tar -czvf linux_arm_v6_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key conf/server.pem web/views web/static nps
|
|
||||||
|
|
||||||
|
|
||||||
CGO_ENABLED=0 GOOS=linux GOARCH=arm GOARM=7 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go
|
|
||||||
tar -czvf linux_arm_v7_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key conf/server.pem web/views web/static nps
|
|
||||||
|
|
||||||
|
|
||||||
CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go
|
|
||||||
tar -czvf linux_arm64_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key conf/server.pem web/views web/static nps
|
|
||||||
|
|
||||||
|
|
||||||
CGO_ENABLED=0 GOOS=freebsd GOARCH=arm go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go
|
|
||||||
tar -czvf freebsd_arm_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key conf/server.pem web/views web/static nps
|
|
||||||
|
|
||||||
|
|
||||||
CGO_ENABLED=0 GOOS=freebsd GOARCH=386 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go
|
|
||||||
tar -czvf freebsd_386_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key conf/server.pem web/views web/static nps
|
|
||||||
|
|
||||||
|
|
||||||
CGO_ENABLED=0 GOOS=freebsd GOARCH=amd64 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go
|
|
||||||
tar -czvf freebsd_amd64_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key conf/server.pem web/views web/static nps
|
|
||||||
|
|
||||||
|
|
||||||
CGO_ENABLED=0 GOOS=linux GOARCH=mips go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go
|
|
||||||
tar -czvf linux_mips_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key conf/server.pem web/views web/static nps
|
|
||||||
|
|
||||||
|
|
||||||
CGO_ENABLED=0 GOOS=linux GOARCH=mips64 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go
|
|
||||||
tar -czvf linux_mips64_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key conf/server.pem web/views web/static nps
|
|
||||||
|
|
||||||
|
|
||||||
CGO_ENABLED=0 GOOS=linux GOARCH=mips64le go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go
|
|
||||||
tar -czvf linux_mips64le_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key conf/server.pem web/views web/static nps
|
|
||||||
|
|
||||||
|
|
||||||
CGO_ENABLED=0 GOOS=linux GOARCH=mipsle go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go
|
|
||||||
tar -czvf linux_mipsle_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key conf/server.pem web/views web/static nps
|
|
||||||
|
|
||||||
|
|
||||||
CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go
|
|
||||||
tar -czvf darwin_amd64_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key conf/server.pem web/views web/static nps
|
|
||||||
|
|
||||||
|
|
||||||
CGO_ENABLED=0 GOOS=darwin GOARCH=arm64 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go
|
|
||||||
tar -czvf darwin_arm64_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key conf/server.pem web/views web/static nps
|
|
||||||
|
|
||||||
|
|
||||||
CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go
|
|
||||||
tar -czvf windows_amd64_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key conf/server.pem web/views web/static nps.exe
|
|
||||||
|
|
||||||
|
|
||||||
CGO_ENABLED=0 GOOS=windows GOARCH=386 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go
|
|
||||||
tar -czvf windows_386_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key conf/server.pem web/views web/static nps.exe
|
|
||||||
|
|
||||||
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
|
|
||||||
sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
|
|
||||||
sudo apt-get update
|
|
||||||
sudo apt-get -y -o Dpkg::Options::="--force-confnew" install docker-ce
|
|
||||||
docker --version
|
|
||||||
docker run --rm -i -w /app -v $(pwd):/app -e ANDROID_HOME=/usr/local/android_sdk -e GOPROXY=direct lucor/fyne-cross:android-latest /app/build.android.sh
|
|
||||||
git clone https://github.com/cnlh/spksrc.git ~/spksrc
|
|
||||||
mkdir ~/spksrc/nps && cp -rf ./* ~/spksrc/nps/
|
|
||||||
docker run -itd --name spksrc --env VERSION=$VERSION -e GOPROXY=direct -v ~/spksrc:/spksrc synocommunity/spksrc /bin/bash
|
|
||||||
docker exec -it spksrc /bin/bash -c 'cd /spksrc && make setup && cd /spksrc/spk/npc && make arch-x64-7.0'
|
|
||||||
cp ~/spksrc/packages/npc_x64-7.0_$VERSION-1.spk ./npc_syno.spk
|
|
||||||
|
|
||||||
|
|
||||||
echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin
|
|
||||||
export DOCKER_CLI_EXPERIMENTAL=enabled
|
|
||||||
docker run --rm --privileged docker/binfmt:66f9012c56a8316f9244ffd7622d7c21c1f6f28d
|
|
||||||
docker buildx create --use --name mybuilder
|
|
||||||
docker buildx build --tag ffdfgdfg/nps:$VERSION --tag ffdfgdfg/nps:latest --output type=image,push=true --file Dockerfile.nps --platform=linux/amd64,linux/arm64,linux/386,linux/arm .
|
|
||||||
docker buildx build --tag ffdfgdfg/npc:$VERSION --tag ffdfgdfg/npc:latest --output type=image,push=true --file Dockerfile.npc --platform=linux/amd64,linux/arm64,linux/386,linux/arm .
|
|
117
client/client.go
117
client/client.go
@ -2,21 +2,18 @@ package client
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
"bytes"
|
|
||||||
"ehang.io/nps-mux"
|
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
"sync"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/astaxie/beego/logs"
|
"github.com/astaxie/beego/logs"
|
||||||
|
"github.com/cnlh/nps/lib/common"
|
||||||
|
"github.com/cnlh/nps/lib/config"
|
||||||
|
"github.com/cnlh/nps/lib/conn"
|
||||||
|
"github.com/cnlh/nps/lib/crypt"
|
||||||
|
"github.com/cnlh/nps/lib/mux"
|
||||||
"github.com/xtaci/kcp-go"
|
"github.com/xtaci/kcp-go"
|
||||||
|
|
||||||
"ehang.io/nps/lib/common"
|
|
||||||
"ehang.io/nps/lib/config"
|
|
||||||
"ehang.io/nps/lib/conn"
|
|
||||||
"ehang.io/nps/lib/crypt"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type TRPClient struct {
|
type TRPClient struct {
|
||||||
@ -25,16 +22,14 @@ type TRPClient struct {
|
|||||||
proxyUrl string
|
proxyUrl string
|
||||||
vKey string
|
vKey string
|
||||||
p2pAddr map[string]string
|
p2pAddr map[string]string
|
||||||
tunnel *nps_mux.Mux
|
tunnel *mux.Mux
|
||||||
signal *conn.Conn
|
signal *conn.Conn
|
||||||
ticker *time.Ticker
|
ticker *time.Ticker
|
||||||
cnf *config.Config
|
cnf *config.Config
|
||||||
disconnectTime int
|
|
||||||
once sync.Once
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//new client
|
//new client
|
||||||
func NewRPClient(svraddr string, vKey string, bridgeConnType string, proxyUrl string, cnf *config.Config, disconnectTime int) *TRPClient {
|
func NewRPClient(svraddr string, vKey string, bridgeConnType string, proxyUrl string, cnf *config.Config) *TRPClient {
|
||||||
return &TRPClient{
|
return &TRPClient{
|
||||||
svrAddr: svraddr,
|
svrAddr: svraddr,
|
||||||
p2pAddr: make(map[string]string, 0),
|
p2pAddr: make(map[string]string, 0),
|
||||||
@ -42,25 +37,15 @@ func NewRPClient(svraddr string, vKey string, bridgeConnType string, proxyUrl st
|
|||||||
bridgeConnType: bridgeConnType,
|
bridgeConnType: bridgeConnType,
|
||||||
proxyUrl: proxyUrl,
|
proxyUrl: proxyUrl,
|
||||||
cnf: cnf,
|
cnf: cnf,
|
||||||
disconnectTime: disconnectTime,
|
|
||||||
once: sync.Once{},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var NowStatus int
|
|
||||||
var CloseClient bool
|
|
||||||
|
|
||||||
//start
|
//start
|
||||||
func (s *TRPClient) Start() {
|
func (s *TRPClient) Start() {
|
||||||
CloseClient = false
|
|
||||||
retry:
|
retry:
|
||||||
if CloseClient {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
NowStatus = 0
|
|
||||||
c, err := NewConn(s.bridgeConnType, s.vKey, s.svrAddr, common.WORK_MAIN, s.proxyUrl)
|
c, err := NewConn(s.bridgeConnType, s.vKey, s.svrAddr, common.WORK_MAIN, s.proxyUrl)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logs.Error("The connection server failed and will be reconnected in five seconds, error", err.Error())
|
logs.Error("The connection server failed and will be reconnected in five seconds")
|
||||||
time.Sleep(time.Second * 5)
|
time.Sleep(time.Second * 5)
|
||||||
goto retry
|
goto retry
|
||||||
}
|
}
|
||||||
@ -79,7 +64,6 @@ retry:
|
|||||||
if s.cnf != nil && len(s.cnf.Healths) > 0 {
|
if s.cnf != nil && len(s.cnf.Healths) > 0 {
|
||||||
go heathCheck(s.cnf.Healths, s.signal)
|
go heathCheck(s.cnf.Healths, s.signal)
|
||||||
}
|
}
|
||||||
NowStatus = 1
|
|
||||||
//msg connection, eg udp
|
//msg connection, eg udp
|
||||||
s.handleMain()
|
s.handleMain()
|
||||||
}
|
}
|
||||||
@ -143,7 +127,7 @@ func (s *TRPClient) newUdpConn(localAddr, rAddr string, md5Password string) {
|
|||||||
conn.SetUdpSession(udpTunnel)
|
conn.SetUdpSession(udpTunnel)
|
||||||
logs.Trace("successful connection with client ,address %s", udpTunnel.RemoteAddr().String())
|
logs.Trace("successful connection with client ,address %s", udpTunnel.RemoteAddr().String())
|
||||||
//read link info from remote
|
//read link info from remote
|
||||||
conn.Accept(nps_mux.NewMux(udpTunnel, s.bridgeConnType, s.disconnectTime), func(c net.Conn) {
|
conn.Accept(mux.NewMux(udpTunnel, s.bridgeConnType), func(c net.Conn) {
|
||||||
go s.handleChan(c)
|
go s.handleChan(c)
|
||||||
})
|
})
|
||||||
break
|
break
|
||||||
@ -151,14 +135,14 @@ func (s *TRPClient) newUdpConn(localAddr, rAddr string, md5Password string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//pmux tunnel
|
//mux tunnel
|
||||||
func (s *TRPClient) newChan() {
|
func (s *TRPClient) newChan() {
|
||||||
tunnel, err := NewConn(s.bridgeConnType, s.vKey, s.svrAddr, common.WORK_CHAN, s.proxyUrl)
|
tunnel, err := NewConn(s.bridgeConnType, s.vKey, s.svrAddr, common.WORK_CHAN, s.proxyUrl)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logs.Error("connect to ", s.svrAddr, "error:", err)
|
logs.Error("connect to ", s.svrAddr, "error:", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
s.tunnel = nps_mux.NewMux(tunnel.Conn, s.bridgeConnType, s.disconnectTime)
|
s.tunnel = mux.NewMux(tunnel.Conn, s.bridgeConnType)
|
||||||
for {
|
for {
|
||||||
src, err := s.tunnel.Accept()
|
src, err := s.tunnel.Accept()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -172,7 +156,7 @@ func (s *TRPClient) newChan() {
|
|||||||
|
|
||||||
func (s *TRPClient) handleChan(src net.Conn) {
|
func (s *TRPClient) handleChan(src net.Conn) {
|
||||||
lk, err := conn.NewConn(src).GetLinkInfo()
|
lk, err := conn.NewConn(src).GetLinkInfo()
|
||||||
if err != nil || lk == nil {
|
if err != nil {
|
||||||
src.Close()
|
src.Close()
|
||||||
logs.Error("get connection info from server error ", err)
|
logs.Error("get connection info from server error ", err)
|
||||||
return
|
return
|
||||||
@ -181,7 +165,7 @@ func (s *TRPClient) handleChan(src net.Conn) {
|
|||||||
lk.Host = common.FormatAddress(lk.Host)
|
lk.Host = common.FormatAddress(lk.Host)
|
||||||
//if Conn type is http, read the request and log
|
//if Conn type is http, read the request and log
|
||||||
if lk.ConnType == "http" {
|
if lk.ConnType == "http" {
|
||||||
if targetConn, err := net.DialTimeout(common.CONN_TCP, lk.Host, lk.Option.Timeout); err != nil {
|
if targetConn, err := net.Dial(common.CONN_TCP, lk.Host); err != nil {
|
||||||
logs.Warn("connect to %s error %s", lk.Host, err.Error())
|
logs.Warn("connect to %s error %s", lk.Host, err.Error())
|
||||||
src.Close()
|
src.Close()
|
||||||
} else {
|
} else {
|
||||||
@ -204,12 +188,8 @@ func (s *TRPClient) handleChan(src net.Conn) {
|
|||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if lk.ConnType == "udp5" {
|
|
||||||
logs.Trace("new %s connection with the goal of %s, remote address:%s", lk.ConnType, lk.Host, lk.RemoteAddr)
|
|
||||||
s.handleUdp(src)
|
|
||||||
}
|
|
||||||
//connect to target if conn type is tcp or udp
|
//connect to target if conn type is tcp or udp
|
||||||
if targetConn, err := net.DialTimeout(lk.ConnType, lk.Host, lk.Option.Timeout); err != nil {
|
if targetConn, err := net.Dial(lk.ConnType, lk.Host); err != nil {
|
||||||
logs.Warn("connect to %s error %s", lk.Host, err.Error())
|
logs.Warn("connect to %s error %s", lk.Host, err.Error())
|
||||||
src.Close()
|
src.Close()
|
||||||
} else {
|
} else {
|
||||||
@ -218,65 +198,6 @@ func (s *TRPClient) handleChan(src net.Conn) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *TRPClient) handleUdp(serverConn net.Conn) {
|
|
||||||
// bind a local udp port
|
|
||||||
local, err := net.ListenUDP("udp", nil)
|
|
||||||
defer serverConn.Close()
|
|
||||||
if err != nil {
|
|
||||||
logs.Error("bind local udp port error ", err.Error())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
defer local.Close()
|
|
||||||
go func() {
|
|
||||||
defer serverConn.Close()
|
|
||||||
b := common.BufPoolUdp.Get().([]byte)
|
|
||||||
defer common.BufPoolUdp.Put(b)
|
|
||||||
for {
|
|
||||||
n, raddr, err := local.ReadFrom(b)
|
|
||||||
if err != nil {
|
|
||||||
logs.Error("read data from remote server error", err.Error())
|
|
||||||
}
|
|
||||||
buf := bytes.Buffer{}
|
|
||||||
dgram := common.NewUDPDatagram(common.NewUDPHeader(0, 0, common.ToSocksAddr(raddr)), b[:n])
|
|
||||||
dgram.Write(&buf)
|
|
||||||
b, err := conn.GetLenBytes(buf.Bytes())
|
|
||||||
if err != nil {
|
|
||||||
logs.Warn("get len bytes error", err.Error())
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if _, err := serverConn.Write(b); err != nil {
|
|
||||||
logs.Error("write data to remote error", err.Error())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
b := common.BufPoolUdp.Get().([]byte)
|
|
||||||
defer common.BufPoolUdp.Put(b)
|
|
||||||
for {
|
|
||||||
n, err := serverConn.Read(b)
|
|
||||||
if err != nil {
|
|
||||||
logs.Error("read udp data from server error ", err.Error())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
udpData, err := common.ReadUDPDatagram(bytes.NewReader(b[:n]))
|
|
||||||
if err != nil {
|
|
||||||
logs.Error("unpack data error", err.Error())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
raddr, err := net.ResolveUDPAddr("udp", udpData.Header.Addr.String())
|
|
||||||
if err != nil {
|
|
||||||
logs.Error("build remote addr err", err.Error())
|
|
||||||
continue // drop silently
|
|
||||||
}
|
|
||||||
_, err = local.WriteTo(udpData.Data, raddr)
|
|
||||||
if err != nil {
|
|
||||||
logs.Error("write data to remote ", raddr.String(), "error", err.Error())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Whether the monitor channel is closed
|
// Whether the monitor channel is closed
|
||||||
func (s *TRPClient) ping() {
|
func (s *TRPClient) ping() {
|
||||||
s.ticker = time.NewTicker(time.Second * 5)
|
s.ticker = time.NewTicker(time.Second * 5)
|
||||||
@ -293,17 +214,11 @@ loop:
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *TRPClient) Close() {
|
func (s *TRPClient) Close() {
|
||||||
s.once.Do(s.closing)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *TRPClient) closing() {
|
|
||||||
CloseClient = true
|
|
||||||
NowStatus = 0
|
|
||||||
if s.tunnel != nil {
|
if s.tunnel != nil {
|
||||||
_ = s.tunnel.Close()
|
s.tunnel.Close()
|
||||||
}
|
}
|
||||||
if s.signal != nil {
|
if s.signal != nil {
|
||||||
_ = s.signal.Close()
|
s.signal.Close()
|
||||||
}
|
}
|
||||||
if s.ticker != nil {
|
if s.ticker != nil {
|
||||||
s.ticker.Stop()
|
s.ticker.Stop()
|
||||||
|
75
client/client_test.go
Normal file
75
client/client_test.go
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
package client
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net"
|
||||||
|
"sync"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/cnlh/nps/lib/common"
|
||||||
|
conn2 "github.com/cnlh/nps/lib/conn"
|
||||||
|
"github.com/cnlh/nps/lib/file"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestConfig(t *testing.T) {
|
||||||
|
conn, err := net.Dial("tcp", "127.0.0.1:8284")
|
||||||
|
if err != nil {
|
||||||
|
t.Fail()
|
||||||
|
}
|
||||||
|
c := conn2.NewConn(conn)
|
||||||
|
c.SetAlive("tcp")
|
||||||
|
if _, err := c.Write([]byte(common.Getverifyval("123"))); err != nil {
|
||||||
|
t.Fail()
|
||||||
|
}
|
||||||
|
c.WriteConfig()
|
||||||
|
config := &file.Config{
|
||||||
|
U: "1",
|
||||||
|
P: "2",
|
||||||
|
Compress: "snappy",
|
||||||
|
Crypt: true,
|
||||||
|
CompressEncode: 0,
|
||||||
|
CompressDecode: 0,
|
||||||
|
}
|
||||||
|
host := &file.Host{
|
||||||
|
Host: "a.o.com",
|
||||||
|
Target: "127.0.0.1:8080",
|
||||||
|
HeaderChange: "",
|
||||||
|
HostChange: "",
|
||||||
|
Flow: nil,
|
||||||
|
Client: nil,
|
||||||
|
Remark: "111",
|
||||||
|
NowIndex: 0,
|
||||||
|
TargetArr: nil,
|
||||||
|
NoStore: false,
|
||||||
|
RWMutex: sync.RWMutex{},
|
||||||
|
}
|
||||||
|
tunnel := &file.Tunnel{
|
||||||
|
Port: 9001,
|
||||||
|
Mode: "tcp",
|
||||||
|
Target: "127.0.0.1:8082",
|
||||||
|
Remark: "333",
|
||||||
|
}
|
||||||
|
var b []byte
|
||||||
|
if b, err = c.ReadLen(16); err != nil {
|
||||||
|
t.Fail()
|
||||||
|
}
|
||||||
|
if _, err := c.SendConfigInfo(config); err != nil {
|
||||||
|
t.Fail()
|
||||||
|
}
|
||||||
|
if !c.GetAddStatus() {
|
||||||
|
t.Fail()
|
||||||
|
}
|
||||||
|
if _, err := c.SendHostInfo(host); err != nil {
|
||||||
|
t.Fail()
|
||||||
|
}
|
||||||
|
if !c.GetAddStatus() {
|
||||||
|
t.Fail()
|
||||||
|
}
|
||||||
|
if _, err := c.SendTaskInfo(tunnel); err != nil {
|
||||||
|
t.Fail()
|
||||||
|
}
|
||||||
|
if !c.GetAddStatus() {
|
||||||
|
t.Fail()
|
||||||
|
}
|
||||||
|
c.Close()
|
||||||
|
NewRPClient("127.0.0.1:8284", string(b), "tcp").Start()
|
||||||
|
}
|
@ -1,7 +1,6 @@
|
|||||||
package client
|
package client
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"errors"
|
"errors"
|
||||||
@ -12,6 +11,7 @@ import (
|
|||||||
"math/rand"
|
"math/rand"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"net/http/httputil"
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
@ -19,12 +19,12 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"ehang.io/nps/lib/common"
|
|
||||||
"ehang.io/nps/lib/config"
|
|
||||||
"ehang.io/nps/lib/conn"
|
|
||||||
"ehang.io/nps/lib/crypt"
|
|
||||||
"ehang.io/nps/lib/version"
|
|
||||||
"github.com/astaxie/beego/logs"
|
"github.com/astaxie/beego/logs"
|
||||||
|
"github.com/cnlh/nps/lib/common"
|
||||||
|
"github.com/cnlh/nps/lib/config"
|
||||||
|
"github.com/cnlh/nps/lib/conn"
|
||||||
|
"github.com/cnlh/nps/lib/crypt"
|
||||||
|
"github.com/cnlh/nps/lib/version"
|
||||||
"github.com/xtaci/kcp-go"
|
"github.com/xtaci/kcp-go"
|
||||||
"golang.org/x/net/proxy"
|
"golang.org/x/net/proxy"
|
||||||
)
|
)
|
||||||
@ -175,7 +175,7 @@ re:
|
|||||||
} else {
|
} else {
|
||||||
logs.Notice("web access login username:%s password:%s", cnf.CommonConfig.Client.WebUserName, cnf.CommonConfig.Client.WebPassword)
|
logs.Notice("web access login username:%s password:%s", cnf.CommonConfig.Client.WebUserName, cnf.CommonConfig.Client.WebPassword)
|
||||||
}
|
}
|
||||||
NewRPClient(cnf.CommonConfig.Server, vkey, cnf.CommonConfig.Tp, cnf.CommonConfig.ProxyUrl, cnf, cnf.CommonConfig.DisconnectTime).Start()
|
NewRPClient(cnf.CommonConfig.Server, vkey, cnf.CommonConfig.Tp, cnf.CommonConfig.ProxyUrl, cnf).Start()
|
||||||
CloseLocalServer()
|
CloseLocalServer()
|
||||||
goto re
|
goto re
|
||||||
}
|
}
|
||||||
@ -198,7 +198,7 @@ func NewConn(tp string, vkey string, server string, connType string, proxyUrl st
|
|||||||
return nil, er
|
return nil, er
|
||||||
}
|
}
|
||||||
connection, err = n.Dial("tcp", server)
|
connection, err = n.Dial("tcp", server)
|
||||||
default:
|
case "http":
|
||||||
connection, err = NewHttpProxyConn(u, server)
|
connection, err = NewHttpProxyConn(u, server)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -220,10 +220,7 @@ func NewConn(tp string, vkey string, server string, connType string, proxyUrl st
|
|||||||
if _, err := c.Write([]byte(common.CONN_TEST)); err != nil {
|
if _, err := c.Write([]byte(common.CONN_TEST)); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if err := c.WriteLenContent([]byte(version.GetVersion())); err != nil {
|
if _, err := c.Write([]byte(crypt.Md5(version.GetVersion()))); err != nil {
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if err := c.WriteLenContent([]byte(version.VERSION)); err != nil {
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
b, err := c.GetShortContent(32)
|
b, err := c.GetShortContent(32)
|
||||||
@ -241,7 +238,8 @@ func NewConn(tp string, vkey string, server string, connType string, proxyUrl st
|
|||||||
if s, err := c.ReadFlag(); err != nil {
|
if s, err := c.ReadFlag(); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else if s == common.VERIFY_EER {
|
} else if s == common.VERIFY_EER {
|
||||||
return nil, errors.New(fmt.Sprintf("Validation key %s incorrect", vkey))
|
logs.Error("Validation key %s incorrect", vkey)
|
||||||
|
os.Exit(0)
|
||||||
}
|
}
|
||||||
if _, err := c.Write([]byte(connType)); err != nil {
|
if _, err := c.Write([]byte(connType)); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -253,28 +251,30 @@ func NewConn(tp string, vkey string, server string, connType string, proxyUrl st
|
|||||||
|
|
||||||
//http proxy connection
|
//http proxy connection
|
||||||
func NewHttpProxyConn(url *url.URL, remoteAddr string) (net.Conn, error) {
|
func NewHttpProxyConn(url *url.URL, remoteAddr string) (net.Conn, error) {
|
||||||
req, err := http.NewRequest("CONNECT", "http://"+remoteAddr, nil)
|
req := &http.Request{
|
||||||
|
Method: "CONNECT",
|
||||||
|
URL: url,
|
||||||
|
Host: remoteAddr,
|
||||||
|
Header: http.Header{},
|
||||||
|
Proto: "HTTP/1.1",
|
||||||
|
}
|
||||||
|
password, _ := url.User.Password()
|
||||||
|
req.Header.Set("Proxy-Authorization", "Basic "+basicAuth(url.User.Username(), password))
|
||||||
|
b, err := httputil.DumpRequest(req, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
password, _ := url.User.Password()
|
|
||||||
req.Header.Set("Authorization", "Basic "+basicAuth(strings.Trim(url.User.Username(), " "), password))
|
|
||||||
// we make a http proxy request
|
|
||||||
proxyConn, err := net.Dial("tcp", url.Host)
|
proxyConn, err := net.Dial("tcp", url.Host)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if err := req.Write(proxyConn); err != nil {
|
if _, err := proxyConn.Write(b); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
res, err := http.ReadResponse(bufio.NewReader(proxyConn), req)
|
buf := make([]byte, 1024)
|
||||||
if err != nil {
|
if _, err := proxyConn.Read(buf); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
_ = res.Body.Close()
|
|
||||||
if res.StatusCode != 200 {
|
|
||||||
return nil, errors.New("Proxy error " + res.Status)
|
|
||||||
}
|
|
||||||
return proxyConn, nil
|
return proxyConn, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -369,7 +369,6 @@ func sendP2PTestMsg(localConn *net.UDPConn, remoteAddr1, remoteAddr2, remoteAddr
|
|||||||
}
|
}
|
||||||
logs.Trace("try send test packet to target %s", addr)
|
logs.Trace("try send test packet to target %s", addr)
|
||||||
ticker := time.NewTicker(time.Millisecond * 500)
|
ticker := time.NewTicker(time.Millisecond * 500)
|
||||||
defer ticker.Stop()
|
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-ticker.C:
|
case <-ticker.C:
|
||||||
@ -395,7 +394,6 @@ func sendP2PTestMsg(localConn *net.UDPConn, remoteAddr1, remoteAddr2, remoteAddr
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
ticker := time.NewTicker(time.Second * 2)
|
ticker := time.NewTicker(time.Second * 2)
|
||||||
defer ticker.Stop()
|
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-ticker.C:
|
case <-ticker.C:
|
||||||
|
@ -7,10 +7,10 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"ehang.io/nps/lib/conn"
|
|
||||||
"ehang.io/nps/lib/file"
|
|
||||||
"ehang.io/nps/lib/sheap"
|
|
||||||
"github.com/astaxie/beego/logs"
|
"github.com/astaxie/beego/logs"
|
||||||
|
"github.com/cnlh/nps/lib/conn"
|
||||||
|
"github.com/cnlh/nps/lib/file"
|
||||||
|
"github.com/cnlh/nps/lib/sheap"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -1,28 +1,26 @@
|
|||||||
package client
|
package client
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"ehang.io/nps-mux"
|
|
||||||
"errors"
|
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"runtime"
|
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"ehang.io/nps/lib/common"
|
|
||||||
"ehang.io/nps/lib/config"
|
|
||||||
"ehang.io/nps/lib/conn"
|
|
||||||
"ehang.io/nps/lib/crypt"
|
|
||||||
"ehang.io/nps/lib/file"
|
|
||||||
"ehang.io/nps/server/proxy"
|
|
||||||
"github.com/astaxie/beego/logs"
|
"github.com/astaxie/beego/logs"
|
||||||
|
"github.com/cnlh/nps/lib/common"
|
||||||
|
"github.com/cnlh/nps/lib/config"
|
||||||
|
"github.com/cnlh/nps/lib/conn"
|
||||||
|
"github.com/cnlh/nps/lib/crypt"
|
||||||
|
"github.com/cnlh/nps/lib/file"
|
||||||
|
"github.com/cnlh/nps/lib/mux"
|
||||||
|
"github.com/cnlh/nps/server/proxy"
|
||||||
"github.com/xtaci/kcp-go"
|
"github.com/xtaci/kcp-go"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
LocalServer []*net.TCPListener
|
LocalServer []*net.TCPListener
|
||||||
udpConn net.Conn
|
udpConn net.Conn
|
||||||
muxSession *nps_mux.Mux
|
muxSession *mux.Mux
|
||||||
fileServer []*http.Server
|
fileServer []*http.Server
|
||||||
p2pNetBridge *p2pBridge
|
p2pNetBridge *p2pBridge
|
||||||
lock sync.RWMutex
|
lock sync.RWMutex
|
||||||
@ -33,14 +31,6 @@ type p2pBridge struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (p2pBridge *p2pBridge) SendLinkInfo(clientId int, link *conn.Link, t *file.Tunnel) (target net.Conn, err error) {
|
func (p2pBridge *p2pBridge) SendLinkInfo(clientId int, link *conn.Link, t *file.Tunnel) (target net.Conn, err error) {
|
||||||
for i := 0; muxSession == nil; i++ {
|
|
||||||
if i >= 20 {
|
|
||||||
err = errors.New("p2pBridge:too many times to get muxSession")
|
|
||||||
logs.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
runtime.Gosched() // waiting for another goroutine establish the mux connection
|
|
||||||
}
|
|
||||||
nowConn, err := muxSession.NewConn()
|
nowConn, err := muxSession.NewConn()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
udpConn = nil
|
udpConn = nil
|
||||||
@ -73,7 +63,7 @@ func startLocalFileServer(config *config.CommonConfig, t *file.Tunnel, vkey stri
|
|||||||
}
|
}
|
||||||
logs.Info("start local file system, local path %s, strip prefix %s ,remote port %s ", t.LocalPath, t.StripPre, t.Ports)
|
logs.Info("start local file system, local path %s, strip prefix %s ,remote port %s ", t.LocalPath, t.StripPre, t.Ports)
|
||||||
fileServer = append(fileServer, srv)
|
fileServer = append(fileServer, srv)
|
||||||
listener := nps_mux.NewMux(remoteConn.Conn, common.CONN_TCP, config.DisconnectTime)
|
listener := mux.NewMux(remoteConn.Conn, common.CONN_TCP)
|
||||||
logs.Error(srv.Serve(listener))
|
logs.Error(srv.Serve(listener))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -127,7 +117,6 @@ func StartLocalServer(l *config.LocalServer, config *config.CommonConfig) error
|
|||||||
|
|
||||||
func handleUdpMonitor(config *config.CommonConfig, l *config.LocalServer) {
|
func handleUdpMonitor(config *config.CommonConfig, l *config.LocalServer) {
|
||||||
ticker := time.NewTicker(time.Second * 1)
|
ticker := time.NewTicker(time.Second * 1)
|
||||||
defer ticker.Stop()
|
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-ticker.C:
|
case <-ticker.C:
|
||||||
@ -168,7 +157,6 @@ func handleP2PVisitor(localTcpConn net.Conn, config *config.CommonConfig, l *con
|
|||||||
if udpConn == nil {
|
if udpConn == nil {
|
||||||
logs.Notice("new conn, P2P can not penetrate successfully, traffic will be transferred through the server")
|
logs.Notice("new conn, P2P can not penetrate successfully, traffic will be transferred through the server")
|
||||||
handleSecret(localTcpConn, config, l)
|
handleSecret(localTcpConn, config, l)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
logs.Trace("start trying to connect with the server")
|
logs.Trace("start trying to connect with the server")
|
||||||
//TODO just support compress now because there is not tls file in client packages
|
//TODO just support compress now because there is not tls file in client packages
|
||||||
@ -214,6 +202,6 @@ func newUdpConn(localAddr string, config *config.CommonConfig, l *config.LocalSe
|
|||||||
logs.Trace("successful create a connection with server", remoteAddress)
|
logs.Trace("successful create a connection with server", remoteAddress)
|
||||||
conn.SetUdpSession(udpTunnel)
|
conn.SetUdpSession(udpTunnel)
|
||||||
udpConn = udpTunnel
|
udpConn = udpTunnel
|
||||||
muxSession = nps_mux.NewMux(udpConn, "kcp", config.DisconnectTime)
|
muxSession = mux.NewMux(udpConn, "kcp")
|
||||||
p2pNetBridge = &p2pBridge{}
|
p2pNetBridge = &p2pBridge{}
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,7 @@ import (
|
|||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"ehang.io/nps/lib/common"
|
"github.com/cnlh/nps/lib/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
func RegisterLocalIp(server string, vKey string, tp string, proxyUrl string, hour int) {
|
func RegisterLocalIp(server string, vKey string, tp string, proxyUrl string, hour int) {
|
||||||
|
222
cmd/npc/npc.go
222
cmd/npc/npc.go
@ -1,105 +1,40 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"ehang.io/nps/client"
|
|
||||||
"ehang.io/nps/lib/common"
|
|
||||||
"ehang.io/nps/lib/config"
|
|
||||||
"ehang.io/nps/lib/file"
|
|
||||||
"ehang.io/nps/lib/install"
|
|
||||||
"ehang.io/nps/lib/version"
|
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/astaxie/beego/logs"
|
"github.com/astaxie/beego/logs"
|
||||||
"github.com/ccding/go-stun/stun"
|
"github.com/ccding/go-stun/stun"
|
||||||
"github.com/kardianos/service"
|
"github.com/cnlh/nps/client"
|
||||||
"os"
|
"github.com/cnlh/nps/lib/common"
|
||||||
"os/exec"
|
"github.com/cnlh/nps/lib/config"
|
||||||
"runtime"
|
"github.com/cnlh/nps/lib/daemon"
|
||||||
"strings"
|
"github.com/cnlh/nps/lib/file"
|
||||||
"sync"
|
"github.com/cnlh/nps/lib/version"
|
||||||
"time"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
serverAddr = flag.String("server", "", "Server addr (ip:port)")
|
serverAddr = flag.String("server", "", "Server addr (ip:port)")
|
||||||
configPath = flag.String("config", "", "Configuration file path")
|
configPath = flag.String("config", "", "Configuration file path")
|
||||||
verifyKey = flag.String("vkey", "", "Authentication key")
|
verifyKey = flag.String("vkey", "", "Authentication key")
|
||||||
logType = flag.String("log", "stdout", "Log output mode(stdout|file)")
|
logType = flag.String("log", "stdout", "Log output mode(stdout|file)")
|
||||||
connType = flag.String("type", "tcp", "Connection type with the server(kcp|tcp)")
|
connType = flag.String("type", "tcp", "Connection type with the server(kcp|tcp)")
|
||||||
proxyUrl = flag.String("proxy", "", "proxy socks5 url(eg:socks5://111:222@127.0.0.1:9007)")
|
proxyUrl = flag.String("proxy", "", "proxy socks5 url(eg:socks5://111:222@127.0.0.1:9007)")
|
||||||
logLevel = flag.String("log_level", "7", "log level 0~7")
|
logLevel = flag.String("log_level", "7", "log level 0~7")
|
||||||
registerTime = flag.Int("time", 2, "register time long /h")
|
registerTime = flag.Int("time", 2, "register time long /h")
|
||||||
localPort = flag.Int("local_port", 2000, "p2p local port")
|
localPort = flag.Int("local_port", 2000, "p2p local port")
|
||||||
password = flag.String("password", "", "p2p password flag")
|
password = flag.String("password", "", "p2p password flag")
|
||||||
target = flag.String("target", "", "p2p target")
|
target = flag.String("target", "", "p2p target")
|
||||||
localType = flag.String("local_type", "p2p", "p2p target")
|
localType = flag.String("local_type", "p2p", "p2p target")
|
||||||
logPath = flag.String("log_path", "", "npc log path")
|
logPath = flag.String("log_path", "npc.log", "npc log path")
|
||||||
debug = flag.Bool("debug", true, "npc debug")
|
|
||||||
pprofAddr = flag.String("pprof", "", "PProf debug addr (ip:port)")
|
|
||||||
stunAddr = flag.String("stun_addr", "stun.stunprotocol.org:3478", "stun server address (eg:stun.stunprotocol.org:3478)")
|
|
||||||
ver = flag.Bool("version", false, "show current version")
|
|
||||||
disconnectTime = flag.Int("disconnect_timeout", 60, "not receiving check packet times, until timeout will disconnect the client")
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
logs.Reset()
|
|
||||||
logs.EnableFuncCallDepth(true)
|
|
||||||
logs.SetLogFuncCallDepth(3)
|
|
||||||
if *ver {
|
|
||||||
common.PrintVersion()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if *logPath == "" {
|
|
||||||
*logPath = common.GetNpcLogPath()
|
|
||||||
}
|
|
||||||
if common.IsWindows() {
|
|
||||||
*logPath = strings.Replace(*logPath, "\\", "\\\\", -1)
|
|
||||||
}
|
|
||||||
if *debug {
|
|
||||||
logs.SetLogger(logs.AdapterConsole, `{"level":`+*logLevel+`,"color":true}`)
|
|
||||||
} else {
|
|
||||||
logs.SetLogger(logs.AdapterFile, `{"level":`+*logLevel+`,"filename":"`+*logPath+`","daily":false,"maxlines":100000,"color":true}`)
|
|
||||||
}
|
|
||||||
|
|
||||||
// init service
|
|
||||||
options := make(service.KeyValue)
|
|
||||||
svcConfig := &service.Config{
|
|
||||||
Name: "Npc",
|
|
||||||
DisplayName: "nps内网穿透客户端",
|
|
||||||
Description: "一款轻量级、功能强大的内网穿透代理服务器。支持tcp、udp流量转发,支持内网http代理、内网socks5代理,同时支持snappy压缩、站点保护、加密传输、多路复用、header修改等。支持web图形化管理,集成多用户模式。",
|
|
||||||
Option: options,
|
|
||||||
}
|
|
||||||
if !common.IsWindows() {
|
|
||||||
svcConfig.Dependencies = []string{
|
|
||||||
"Requires=network.target",
|
|
||||||
"After=network-online.target syslog.target"}
|
|
||||||
svcConfig.Option["SystemdScript"] = install.SystemdScript
|
|
||||||
svcConfig.Option["SysvScript"] = install.SysvScript
|
|
||||||
}
|
|
||||||
for _, v := range os.Args[1:] {
|
|
||||||
switch v {
|
|
||||||
case "install", "start", "stop", "uninstall", "restart":
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if !strings.Contains(v, "-service=") && !strings.Contains(v, "-debug=") {
|
|
||||||
svcConfig.Arguments = append(svcConfig.Arguments, v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
svcConfig.Arguments = append(svcConfig.Arguments, "-debug=false")
|
|
||||||
prg := &npc{
|
|
||||||
exit: make(chan struct{}),
|
|
||||||
}
|
|
||||||
s, err := service.New(prg, svcConfig)
|
|
||||||
if err != nil {
|
|
||||||
logs.Error(err, "service function disabled")
|
|
||||||
run()
|
|
||||||
// run without service
|
|
||||||
wg := sync.WaitGroup{}
|
|
||||||
wg.Add(1)
|
|
||||||
wg.Wait()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if len(os.Args) >= 2 {
|
if len(os.Args) >= 2 {
|
||||||
switch os.Args[1] {
|
switch os.Args[1] {
|
||||||
case "status":
|
case "status":
|
||||||
@ -110,101 +45,24 @@ func main() {
|
|||||||
case "register":
|
case "register":
|
||||||
flag.CommandLine.Parse(os.Args[2:])
|
flag.CommandLine.Parse(os.Args[2:])
|
||||||
client.RegisterLocalIp(*serverAddr, *verifyKey, *connType, *proxyUrl, *registerTime)
|
client.RegisterLocalIp(*serverAddr, *verifyKey, *connType, *proxyUrl, *registerTime)
|
||||||
case "update":
|
|
||||||
install.UpdateNpc()
|
|
||||||
return
|
|
||||||
case "nat":
|
case "nat":
|
||||||
c := stun.NewClient()
|
nat, host, err := stun.NewClient().Discover()
|
||||||
c.SetServerAddr(*stunAddr)
|
|
||||||
nat, host, err := c.Discover()
|
|
||||||
if err != nil || host == nil {
|
if err != nil || host == nil {
|
||||||
logs.Error("get nat type error", err)
|
logs.Error("get nat type error", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
fmt.Printf("nat type: %s \npublic address: %s\n", nat.String(), host.String())
|
fmt.Printf("nat type: %s \npublic address: %s\n", nat.String(), host.String())
|
||||||
os.Exit(0)
|
os.Exit(0)
|
||||||
case "start", "stop", "restart":
|
|
||||||
// support busyBox and sysV, for openWrt
|
|
||||||
if service.Platform() == "unix-systemv" {
|
|
||||||
logs.Info("unix-systemv service")
|
|
||||||
cmd := exec.Command("/etc/init.d/"+svcConfig.Name, os.Args[1])
|
|
||||||
err := cmd.Run()
|
|
||||||
if err != nil {
|
|
||||||
logs.Error(err)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
err := service.Control(s, os.Args[1])
|
|
||||||
if err != nil {
|
|
||||||
logs.Error("Valid actions: %q\n%s", service.ControlAction, err.Error())
|
|
||||||
}
|
|
||||||
return
|
|
||||||
case "install":
|
|
||||||
service.Control(s, "stop")
|
|
||||||
service.Control(s, "uninstall")
|
|
||||||
install.InstallNpc()
|
|
||||||
err := service.Control(s, os.Args[1])
|
|
||||||
if err != nil {
|
|
||||||
logs.Error("Valid actions: %q\n%s", service.ControlAction, err.Error())
|
|
||||||
}
|
|
||||||
if service.Platform() == "unix-systemv" {
|
|
||||||
logs.Info("unix-systemv service")
|
|
||||||
confPath := "/etc/init.d/" + svcConfig.Name
|
|
||||||
os.Symlink(confPath, "/etc/rc.d/S90"+svcConfig.Name)
|
|
||||||
os.Symlink(confPath, "/etc/rc.d/K02"+svcConfig.Name)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
case "uninstall":
|
|
||||||
err := service.Control(s, os.Args[1])
|
|
||||||
if err != nil {
|
|
||||||
logs.Error("Valid actions: %q\n%s", service.ControlAction, err.Error())
|
|
||||||
}
|
|
||||||
if service.Platform() == "unix-systemv" {
|
|
||||||
logs.Info("unix-systemv service")
|
|
||||||
os.Remove("/etc/rc.d/S90" + svcConfig.Name)
|
|
||||||
os.Remove("/etc/rc.d/K02" + svcConfig.Name)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
s.Run()
|
daemon.InitDaemon("npc", common.GetRunPath(), common.GetTmpPath())
|
||||||
}
|
logs.EnableFuncCallDepth(true)
|
||||||
|
logs.SetLogFuncCallDepth(3)
|
||||||
type npc struct {
|
if *logType == "stdout" {
|
||||||
exit chan struct{}
|
logs.SetLogger(logs.AdapterConsole, `{"level":`+*logLevel+`,"color":true}`)
|
||||||
}
|
} else {
|
||||||
|
logs.SetLogger(logs.AdapterFile, `{"level":`+*logLevel+`,"filename":"`+*logPath+`","daily":false,"maxlines":100000,"color":true}`)
|
||||||
func (p *npc) Start(s service.Service) error {
|
|
||||||
go p.run()
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
func (p *npc) Stop(s service.Service) error {
|
|
||||||
close(p.exit)
|
|
||||||
if service.Interactive() {
|
|
||||||
os.Exit(0)
|
|
||||||
}
|
}
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *npc) run() error {
|
|
||||||
defer func() {
|
|
||||||
if err := recover(); err != nil {
|
|
||||||
const size = 64 << 10
|
|
||||||
buf := make([]byte, size)
|
|
||||||
buf = buf[:runtime.Stack(buf, false)]
|
|
||||||
logs.Warning("npc: panic serving %v: %v\n%s", err, string(buf))
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
run()
|
|
||||||
select {
|
|
||||||
case <-p.exit:
|
|
||||||
logs.Warning("stop...")
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func run() {
|
|
||||||
common.InitPProfFromArg(*pprofAddr)
|
|
||||||
//p2p or secret command
|
//p2p or secret command
|
||||||
if *password != "" {
|
if *password != "" {
|
||||||
commonConfig := new(config.CommonConfig)
|
commonConfig := new(config.CommonConfig)
|
||||||
@ -218,7 +76,7 @@ func run() {
|
|||||||
localServer.Port = *localPort
|
localServer.Port = *localPort
|
||||||
commonConfig.Client = new(file.Client)
|
commonConfig.Client = new(file.Client)
|
||||||
commonConfig.Client.Cnf = new(file.Config)
|
commonConfig.Client.Cnf = new(file.Config)
|
||||||
go client.StartLocalServer(localServer, commonConfig)
|
client.StartLocalServer(localServer, commonConfig)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
env := common.GetEnvMap()
|
env := common.GetEnvMap()
|
||||||
@ -230,17 +88,15 @@ func run() {
|
|||||||
}
|
}
|
||||||
logs.Info("the version of client is %s, the core version of client is %s", version.VERSION, version.GetVersion())
|
logs.Info("the version of client is %s, the core version of client is %s", version.VERSION, version.GetVersion())
|
||||||
if *verifyKey != "" && *serverAddr != "" && *configPath == "" {
|
if *verifyKey != "" && *serverAddr != "" && *configPath == "" {
|
||||||
go func() {
|
for {
|
||||||
for {
|
client.NewRPClient(*serverAddr, *verifyKey, *connType, *proxyUrl, nil).Start()
|
||||||
client.NewRPClient(*serverAddr, *verifyKey, *connType, *proxyUrl, nil, *disconnectTime).Start()
|
logs.Info("It will be reconnected in five seconds")
|
||||||
logs.Info("Client closed! It will be reconnected in five seconds")
|
time.Sleep(time.Second * 5)
|
||||||
time.Sleep(time.Second * 5)
|
}
|
||||||
}
|
|
||||||
}()
|
|
||||||
} else {
|
} else {
|
||||||
if *configPath == "" {
|
if *configPath == "" {
|
||||||
*configPath = common.GetConfigPath()
|
*configPath = "npc.conf"
|
||||||
}
|
}
|
||||||
go client.StartFromFile(*configPath)
|
client.StartFromFile(*configPath)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,48 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"C"
|
|
||||||
"ehang.io/nps/client"
|
|
||||||
"ehang.io/nps/lib/common"
|
|
||||||
"ehang.io/nps/lib/version"
|
|
||||||
"github.com/astaxie/beego/logs"
|
|
||||||
)
|
|
||||||
|
|
||||||
var cl *client.TRPClient
|
|
||||||
|
|
||||||
//export StartClientByVerifyKey
|
|
||||||
func StartClientByVerifyKey(serverAddr, verifyKey, connType, proxyUrl *C.char) int {
|
|
||||||
_ = logs.SetLogger("store")
|
|
||||||
if cl != nil {
|
|
||||||
cl.Close()
|
|
||||||
}
|
|
||||||
cl = client.NewRPClient(C.GoString(serverAddr), C.GoString(verifyKey), C.GoString(connType), C.GoString(proxyUrl), nil, 60)
|
|
||||||
cl.Start()
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
|
|
||||||
//export GetClientStatus
|
|
||||||
func GetClientStatus() int {
|
|
||||||
return client.NowStatus
|
|
||||||
}
|
|
||||||
|
|
||||||
//export CloseClient
|
|
||||||
func CloseClient() {
|
|
||||||
if cl != nil {
|
|
||||||
cl.Close()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//export Version
|
|
||||||
func Version() *C.char {
|
|
||||||
return C.CString(version.VERSION)
|
|
||||||
}
|
|
||||||
|
|
||||||
//export Logs
|
|
||||||
func Logs() *C.char {
|
|
||||||
return C.CString(common.GetLogMsg())
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
// Need a main function to make CGO compile package as C shared library
|
|
||||||
}
|
|
205
cmd/nps/nps.go
205
cmd/nps/nps.go
@ -4,193 +4,55 @@ import (
|
|||||||
"flag"
|
"flag"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
|
||||||
"strings"
|
|
||||||
"sync"
|
|
||||||
|
|
||||||
"ehang.io/nps/lib/file"
|
|
||||||
"ehang.io/nps/lib/install"
|
|
||||||
"ehang.io/nps/lib/version"
|
|
||||||
"ehang.io/nps/server"
|
|
||||||
"ehang.io/nps/server/connection"
|
|
||||||
"ehang.io/nps/server/tool"
|
|
||||||
"ehang.io/nps/web/routers"
|
|
||||||
|
|
||||||
"ehang.io/nps/lib/common"
|
|
||||||
"ehang.io/nps/lib/crypt"
|
|
||||||
"ehang.io/nps/lib/daemon"
|
|
||||||
"github.com/astaxie/beego"
|
"github.com/astaxie/beego"
|
||||||
"github.com/astaxie/beego/logs"
|
"github.com/astaxie/beego/logs"
|
||||||
|
"github.com/cnlh/nps/lib/common"
|
||||||
"github.com/kardianos/service"
|
"github.com/cnlh/nps/lib/crypt"
|
||||||
|
"github.com/cnlh/nps/lib/daemon"
|
||||||
|
"github.com/cnlh/nps/lib/file"
|
||||||
|
"github.com/cnlh/nps/lib/install"
|
||||||
|
"github.com/cnlh/nps/lib/version"
|
||||||
|
"github.com/cnlh/nps/server"
|
||||||
|
"github.com/cnlh/nps/server/connection"
|
||||||
|
"github.com/cnlh/nps/server/test"
|
||||||
|
"github.com/cnlh/nps/server/tool"
|
||||||
|
_ "github.com/cnlh/nps/web/routers"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
level string
|
level string
|
||||||
ver = flag.Bool("version", false, "show current version")
|
logType = flag.String("log", "stdout", "Log output mode(stdout|file)")
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
// init log
|
beego.LoadAppConfig("ini", filepath.Join(common.GetRunPath(), "conf", "nps.conf"))
|
||||||
if *ver {
|
if len(os.Args) > 1 {
|
||||||
common.PrintVersion()
|
switch os.Args[1] {
|
||||||
return
|
case "test":
|
||||||
|
test.TestServerConfig()
|
||||||
|
log.Println("test ok, no error")
|
||||||
|
return
|
||||||
|
case "start", "restart", "stop", "status", "reload":
|
||||||
|
daemon.InitDaemon("nps", common.GetRunPath(), common.GetTmpPath())
|
||||||
|
case "install":
|
||||||
|
install.InstallNps()
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if err := beego.LoadAppConfig("ini", filepath.Join(common.GetRunPath(), "conf", "nps.conf")); err != nil {
|
|
||||||
log.Fatalln("load config file error", err.Error())
|
|
||||||
}
|
|
||||||
common.InitPProfFromFile()
|
|
||||||
if level = beego.AppConfig.String("log_level"); level == "" {
|
if level = beego.AppConfig.String("log_level"); level == "" {
|
||||||
level = "7"
|
level = "7"
|
||||||
}
|
}
|
||||||
logs.Reset()
|
logs.Reset()
|
||||||
logs.EnableFuncCallDepth(true)
|
logs.EnableFuncCallDepth(true)
|
||||||
logs.SetLogFuncCallDepth(3)
|
logs.SetLogFuncCallDepth(3)
|
||||||
logPath := beego.AppConfig.String("log_path")
|
if *logType == "stdout" {
|
||||||
if logPath == "" {
|
logs.SetLogger(logs.AdapterConsole, `{"level":`+level+`,"color":true}`)
|
||||||
logPath = common.GetLogPath()
|
|
||||||
}
|
|
||||||
if common.IsWindows() {
|
|
||||||
logPath = strings.Replace(logPath, "\\", "\\\\", -1)
|
|
||||||
}
|
|
||||||
// init service
|
|
||||||
options := make(service.KeyValue)
|
|
||||||
svcConfig := &service.Config{
|
|
||||||
Name: "Nps",
|
|
||||||
DisplayName: "nps内网穿透代理服务器",
|
|
||||||
Description: "一款轻量级、功能强大的内网穿透代理服务器。支持tcp、udp流量转发,支持内网http代理、内网socks5代理,同时支持snappy压缩、站点保护、加密传输、多路复用、header修改等。支持web图形化管理,集成多用户模式。",
|
|
||||||
Option: options,
|
|
||||||
}
|
|
||||||
svcConfig.Arguments = append(svcConfig.Arguments, "service")
|
|
||||||
if len(os.Args) > 1 && os.Args[1] == "service" {
|
|
||||||
_ = logs.SetLogger(logs.AdapterFile, `{"level":`+level+`,"filename":"`+logPath+`","daily":false,"maxlines":100000,"color":true}`)
|
|
||||||
} else {
|
} else {
|
||||||
_ = logs.SetLogger(logs.AdapterConsole, `{"level":`+level+`,"color":true}`)
|
logs.SetLogger(logs.AdapterFile, `{"level":`+level+`,"filename":"`+beego.AppConfig.String("log_path")+`","daily":false,"maxlines":100000,"color":true}`)
|
||||||
}
|
}
|
||||||
if !common.IsWindows() {
|
|
||||||
svcConfig.Dependencies = []string{
|
|
||||||
"Requires=network.target",
|
|
||||||
"After=network-online.target syslog.target"}
|
|
||||||
svcConfig.Option["SystemdScript"] = install.SystemdScript
|
|
||||||
svcConfig.Option["SysvScript"] = install.SysvScript
|
|
||||||
}
|
|
||||||
prg := &nps{}
|
|
||||||
prg.exit = make(chan struct{})
|
|
||||||
s, err := service.New(prg, svcConfig)
|
|
||||||
if err != nil {
|
|
||||||
logs.Error(err, "service function disabled")
|
|
||||||
run()
|
|
||||||
// run without service
|
|
||||||
wg := sync.WaitGroup{}
|
|
||||||
wg.Add(1)
|
|
||||||
wg.Wait()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if len(os.Args) > 1 && os.Args[1] != "service" {
|
|
||||||
switch os.Args[1] {
|
|
||||||
case "reload":
|
|
||||||
daemon.InitDaemon("nps", common.GetRunPath(), common.GetTmpPath())
|
|
||||||
return
|
|
||||||
case "install":
|
|
||||||
// uninstall before
|
|
||||||
_ = service.Control(s, "stop")
|
|
||||||
_ = service.Control(s, "uninstall")
|
|
||||||
|
|
||||||
binPath := install.InstallNps()
|
|
||||||
svcConfig.Executable = binPath
|
|
||||||
s, err := service.New(prg, svcConfig)
|
|
||||||
if err != nil {
|
|
||||||
logs.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
err = service.Control(s, os.Args[1])
|
|
||||||
if err != nil {
|
|
||||||
logs.Error("Valid actions: %q\n%s", service.ControlAction, err.Error())
|
|
||||||
}
|
|
||||||
if service.Platform() == "unix-systemv" {
|
|
||||||
logs.Info("unix-systemv service")
|
|
||||||
confPath := "/etc/init.d/" + svcConfig.Name
|
|
||||||
os.Symlink(confPath, "/etc/rc.d/S90"+svcConfig.Name)
|
|
||||||
os.Symlink(confPath, "/etc/rc.d/K02"+svcConfig.Name)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
case "start", "restart", "stop":
|
|
||||||
if service.Platform() == "unix-systemv" {
|
|
||||||
logs.Info("unix-systemv service")
|
|
||||||
cmd := exec.Command("/etc/init.d/"+svcConfig.Name, os.Args[1])
|
|
||||||
err := cmd.Run()
|
|
||||||
if err != nil {
|
|
||||||
logs.Error(err)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
err := service.Control(s, os.Args[1])
|
|
||||||
if err != nil {
|
|
||||||
logs.Error("Valid actions: %q\n%s", service.ControlAction, err.Error())
|
|
||||||
}
|
|
||||||
return
|
|
||||||
case "uninstall":
|
|
||||||
err := service.Control(s, os.Args[1])
|
|
||||||
if err != nil {
|
|
||||||
logs.Error("Valid actions: %q\n%s", service.ControlAction, err.Error())
|
|
||||||
}
|
|
||||||
if service.Platform() == "unix-systemv" {
|
|
||||||
logs.Info("unix-systemv service")
|
|
||||||
os.Remove("/etc/rc.d/S90" + svcConfig.Name)
|
|
||||||
os.Remove("/etc/rc.d/K02" + svcConfig.Name)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
case "update":
|
|
||||||
install.UpdateNps()
|
|
||||||
return
|
|
||||||
default:
|
|
||||||
logs.Error("command is not support")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ = s.Run()
|
|
||||||
}
|
|
||||||
|
|
||||||
type nps struct {
|
|
||||||
exit chan struct{}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *nps) Start(s service.Service) error {
|
|
||||||
_, _ = s.Status()
|
|
||||||
go p.run()
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
func (p *nps) Stop(s service.Service) error {
|
|
||||||
_, _ = s.Status()
|
|
||||||
close(p.exit)
|
|
||||||
if service.Interactive() {
|
|
||||||
os.Exit(0)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *nps) run() error {
|
|
||||||
defer func() {
|
|
||||||
if err := recover(); err != nil {
|
|
||||||
const size = 64 << 10
|
|
||||||
buf := make([]byte, size)
|
|
||||||
buf = buf[:runtime.Stack(buf, false)]
|
|
||||||
logs.Warning("nps: panic serving %v: %v\n%s", err, string(buf))
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
run()
|
|
||||||
select {
|
|
||||||
case <-p.exit:
|
|
||||||
logs.Warning("stop...")
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func run() {
|
|
||||||
routers.Init()
|
|
||||||
task := &file.Tunnel{
|
task := &file.Tunnel{
|
||||||
Mode: "webServer",
|
Mode: "webServer",
|
||||||
}
|
}
|
||||||
@ -201,13 +63,8 @@ func run() {
|
|||||||
}
|
}
|
||||||
logs.Info("the version of server is %s ,allow client core version to be %s", version.VERSION, version.GetVersion())
|
logs.Info("the version of server is %s ,allow client core version to be %s", version.VERSION, version.GetVersion())
|
||||||
connection.InitConnectionService()
|
connection.InitConnectionService()
|
||||||
//crypt.InitTls(filepath.Join(common.GetRunPath(), "conf", "server.pem"), filepath.Join(common.GetRunPath(), "conf", "server.key"))
|
crypt.InitTls(filepath.Join(common.GetRunPath(), "conf", "server.pem"), filepath.Join(common.GetRunPath(), "conf", "server.key"))
|
||||||
crypt.InitTls()
|
|
||||||
tool.InitAllowPort()
|
tool.InitAllowPort()
|
||||||
tool.StartSystemInfo()
|
tool.StartSystemInfo()
|
||||||
timeout, err := beego.AppConfig.Int("disconnect_timeout")
|
server.StartNewServer(bridgePort, task, beego.AppConfig.String("bridge_type"))
|
||||||
if err != nil {
|
|
||||||
timeout = 60
|
|
||||||
}
|
|
||||||
go server.StartNewServer(bridgePort, task, beego.AppConfig.String("bridge_type"), timeout)
|
|
||||||
}
|
}
|
||||||
|
@ -12,8 +12,6 @@ web_username=user
|
|||||||
web_password=1234
|
web_password=1234
|
||||||
crypt=true
|
crypt=true
|
||||||
compress=true
|
compress=true
|
||||||
#pprof_addr=0.0.0.0:9999
|
|
||||||
disconnect_timeout=60
|
|
||||||
|
|
||||||
[health_check_test1]
|
[health_check_test1]
|
||||||
health_check_timeout=1
|
health_check_timeout=1
|
||||||
|
@ -26,7 +26,7 @@ public_vkey=123
|
|||||||
|
|
||||||
# log level LevelEmergency->0 LevelAlert->1 LevelCritical->2 LevelError->3 LevelWarning->4 LevelNotice->5 LevelInformational->6 LevelDebug->7
|
# log level LevelEmergency->0 LevelAlert->1 LevelCritical->2 LevelError->3 LevelWarning->4 LevelNotice->5 LevelInformational->6 LevelDebug->7
|
||||||
log_level=7
|
log_level=7
|
||||||
#log_path=nps.log
|
log_path=nps.log
|
||||||
|
|
||||||
#Whether to restrict IP access, true or false or ignore
|
#Whether to restrict IP access, true or false or ignore
|
||||||
#ip_limit=true
|
#ip_limit=true
|
||||||
@ -41,16 +41,9 @@ web_username=admin
|
|||||||
web_password=123
|
web_password=123
|
||||||
web_port = 8080
|
web_port = 8080
|
||||||
web_ip=0.0.0.0
|
web_ip=0.0.0.0
|
||||||
web_base_url=
|
|
||||||
web_open_ssl=false
|
|
||||||
web_cert_file=conf/server.pem
|
|
||||||
web_key_file=conf/server.key
|
|
||||||
# if web under proxy use sub path. like http://host/nps need this.
|
|
||||||
#web_base_url=/nps
|
|
||||||
|
|
||||||
#Web API unauthenticated IP address(the len of auth_crypt_key must be 16)
|
#Web API unauthenticated IP address(the len of auth_crypt_key must be 16)
|
||||||
#Remove comments if needed
|
auth_key=test
|
||||||
#auth_key=test
|
|
||||||
auth_crypt_key =1234567812345678
|
auth_crypt_key =1234567812345678
|
||||||
|
|
||||||
#allow_ports=9001-9009,10001,11000-12000
|
#allow_ports=9001-9009,10001,11000-12000
|
||||||
@ -74,12 +67,4 @@ system_info_display=false
|
|||||||
http_cache=false
|
http_cache=false
|
||||||
http_cache_length=100
|
http_cache_length=100
|
||||||
|
|
||||||
#get origin ip
|
|
||||||
http_add_origin_header=false
|
|
||||||
|
|
||||||
#pprof debug options
|
|
||||||
#pprof_ip=0.0.0.0
|
|
||||||
#pprof_port=9999
|
|
||||||
|
|
||||||
#client disconnect timeout
|
|
||||||
disconnect_timeout=60
|
|
||||||
|
@ -1,21 +0,0 @@
|
|||||||
# nps
|
|
||||||
 
|
|
||||||
[](https://gitter.im/cnlh-nps/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
|
|
||||||
[](https://travis-ci.org/cnlh/nps)
|
|
||||||
|
|
||||||
nps是一款轻量级、高性能、功能强大的**内网穿透**代理服务器。目前支持**tcp、udp流量转发**,可支持任何**tcp、udp**上层协议(访问内网网站、本地支付接口调试、ssh访问、远程桌面,内网dns解析等等……),此外还**支持内网http代理、内网socks5代理**、**p2p等**,并带有功能强大的web管理端。
|
|
||||||
|
|
||||||
|
|
||||||
## 背景
|
|
||||||

|
|
||||||
|
|
||||||
1. 做微信公众号开发、小程序开发等----> 域名代理模式
|
|
||||||
|
|
||||||
|
|
||||||
2. 想在外网通过ssh连接内网的机器,做云服务器到内网服务器端口的映射,----> tcp代理模式
|
|
||||||
|
|
||||||
3. 在非内网环境下使用内网dns,或者需要通过udp访问内网机器等----> udp代理模式
|
|
||||||
|
|
||||||
4. 在外网使用HTTP代理访问内网站点----> http代理模式
|
|
||||||
|
|
||||||
5. 搭建一个内网穿透ss,在外网如同使用内网vpn一样访问内网资源或者设备----> socks5代理模式
|
|
@ -1,16 +0,0 @@
|
|||||||

|
|
||||||
|
|
||||||
# NPS <small>0.26.10</small>
|
|
||||||
|
|
||||||
> 一款轻量级、高性能、功能强大的内网穿透代理服务器
|
|
||||||
|
|
||||||
- 几乎支持所有协议
|
|
||||||
- 支持内网http代理、内网socks5代理、p2p等
|
|
||||||
- 简洁但功能强大的WEB管理界面
|
|
||||||
- 支持服务端、客户端同时控制
|
|
||||||
- 扩展功能强大
|
|
||||||
- 全平台兼容,一键注册为服务
|
|
||||||
|
|
||||||
|
|
||||||
[GitHub](https://github.com/ehang-io/nps/)
|
|
||||||
[开始使用](#nps)
|
|
@ -1,3 +0,0 @@
|
|||||||
* [](https://github.com/ehang-io/nps/stargazers)
|
|
||||||
|
|
||||||
* [](https://github.com/ehang-io/nps/network)
|
|
@ -1,29 +0,0 @@
|
|||||||
* 入门
|
|
||||||
* [安装](install.md)
|
|
||||||
* [启动](run.md)
|
|
||||||
* [使用示例](example.md)
|
|
||||||
* 服务端
|
|
||||||
* [介绍](introduction.md)
|
|
||||||
* [使用](nps_use.md)
|
|
||||||
* [配置文件](server_config.md)
|
|
||||||
* [增强功能](nps_extend.md)
|
|
||||||
|
|
||||||
* 客户端
|
|
||||||
|
|
||||||
* [基本使用](use.md)
|
|
||||||
* [增强功能](npc_extend.md)
|
|
||||||
|
|
||||||
* 扩展
|
|
||||||
|
|
||||||
* [功能](feature.md)
|
|
||||||
* [说明](description.md)
|
|
||||||
* [web api](api.md)
|
|
||||||
* [sdk](npc_sdk.md)
|
|
||||||
|
|
||||||
* 其他
|
|
||||||
|
|
||||||
* [FAQ](faq.md)
|
|
||||||
* [贡献](contribute.md)
|
|
||||||
* [捐助](donate.md)
|
|
||||||
* [致谢](thanks.md)
|
|
||||||
* [交流](discuss.md)
|
|
45
docs/api.md
45
docs/api.md
@ -1,45 +0,0 @@
|
|||||||
# web api
|
|
||||||
|
|
||||||
需要开启请先去掉`nps.conf`中`auth_key`的注释并配置一个合适的密钥
|
|
||||||
## webAPI验证说明
|
|
||||||
- 采用auth_key的验证方式
|
|
||||||
- 在提交的每个请求后面附带两个参数,`auth_key` 和`timestamp`
|
|
||||||
|
|
||||||
```
|
|
||||||
auth_key的生成方式为:md5(配置文件中的auth_key+当前时间戳)
|
|
||||||
```
|
|
||||||
|
|
||||||
```
|
|
||||||
timestamp为当前时间戳
|
|
||||||
```
|
|
||||||
```
|
|
||||||
curl --request POST \
|
|
||||||
--url http://127.0.0.1:8080/client/list \
|
|
||||||
--data 'auth_key=2a0000d9229e7dbcf79dd0f5e04bb084×tamp=1553045344&start=0&limit=10'
|
|
||||||
```
|
|
||||||
**注意:** 为保证安全,时间戳的有效范围为20秒内,所以每次提交请求必须重新生成。
|
|
||||||
|
|
||||||
## 获取服务端时间
|
|
||||||
由于服务端与api请求的客户端时间差异不能太大,所以提供了一个可以获取服务端时间的接口
|
|
||||||
|
|
||||||
```
|
|
||||||
POST /auth/gettime
|
|
||||||
```
|
|
||||||
|
|
||||||
## 获取服务端authKey
|
|
||||||
|
|
||||||
如果想获取authKey,服务端提供获取authKey的接口
|
|
||||||
|
|
||||||
```
|
|
||||||
POST /auth/getauthkey
|
|
||||||
```
|
|
||||||
将返回加密后的authKey,采用aes cbc加密,请使用与服务端配置文件中cryptKey相同的密钥进行解密
|
|
||||||
|
|
||||||
**注意:** nps配置文件中`auth_crypt_key`需为16位
|
|
||||||
- 解密密钥长度128
|
|
||||||
- 偏移量与密钥相同
|
|
||||||
- 补码方式pkcs5padding
|
|
||||||
- 解密串编码方式 十六进制
|
|
||||||
|
|
||||||
## 详细文档
|
|
||||||
- **[详见](webapi.md)** (感谢@avengexyz)
|
|
@ -1,6 +0,0 @@
|
|||||||
# 贡献
|
|
||||||
|
|
||||||
- 如果遇到bug可以直接提交至dev分支
|
|
||||||
- 使用遇到问题可以通过issues反馈
|
|
||||||
- 项目处于开发阶段,还有很多待完善的地方,如果可以贡献代码,请提交 PR 至 dev 分支
|
|
||||||
- 如果有新的功能特性反馈,可以通过issues或者qq群反馈
|
|
@ -1,30 +0,0 @@
|
|||||||
# 说明
|
|
||||||
## 获取用户真实ip
|
|
||||||
如需使用需要在`nps.conf`中设置`http_add_origin_header=true`
|
|
||||||
|
|
||||||
在域名代理模式中,可以通过request请求 header 中的 X-Forwarded-For 和 X-Real-IP 来获取用户真实 IP。
|
|
||||||
|
|
||||||
**本代理前会在每一个http(s)请求中添加了这两个 header。**
|
|
||||||
|
|
||||||
## 热更新支持
|
|
||||||
对于绝大多数配置,在web管理中的修改将实时使用,无需重启客户端或者服务端
|
|
||||||
|
|
||||||
## 客户端地址显示
|
|
||||||
在web管理中将显示客户端的连接地址
|
|
||||||
|
|
||||||
## 流量统计
|
|
||||||
可统计显示每个代理使用的流量,由于压缩和加密等原因,会和实际环境中的略有差异
|
|
||||||
|
|
||||||
## 当前客户端带宽
|
|
||||||
可统计每个客户端当前的带宽,可能和实际有一定差异,仅供参考。
|
|
||||||
|
|
||||||
## 客户端与服务端版本对比
|
|
||||||
为了程序正常运行,客户端与服务端的核心版本必须一致,否则将导致客户端无法成功连接致服务端。
|
|
||||||
|
|
||||||
## Linux系统限制
|
|
||||||
默认情况下linux对连接数量有限制,对于性能好的机器完全可以调整内核参数以处理更多的连接。
|
|
||||||
`tcp_max_syn_backlog` `somaxconn`
|
|
||||||
酌情调整参数,增强网络性能
|
|
||||||
|
|
||||||
## web管理保护
|
|
||||||
当一个ip连续登陆失败次数超过10次,将在一分钟内禁止该ip再次尝试。
|
|
@ -1,3 +0,0 @@
|
|||||||
# 交流群
|
|
||||||
|
|
||||||

|
|
@ -1,7 +0,0 @@
|
|||||||
# 捐助
|
|
||||||
如果您觉得nps对你有帮助,欢迎给予我们一定捐助,也是帮助nps更好的发展。
|
|
||||||
|
|
||||||
## 支付宝
|
|
||||||

|
|
||||||
## 微信
|
|
||||||

|
|
126
docs/example.md
126
docs/example.md
@ -1,126 +0,0 @@
|
|||||||
# 使用示例
|
|
||||||
## 统一准备工作(必做)
|
|
||||||
- 开启服务端,假设公网服务器ip为1.1.1.1,配置文件中`bridge_port`为8024,配置文件中`web_port`为8080
|
|
||||||
- 访问1.1.1.1:8080
|
|
||||||
- 在客户端管理中创建一个客户端,记录下验证密钥
|
|
||||||
- 内网客户端运行(windows使用cmd运行加.exe)
|
|
||||||
|
|
||||||
```shell
|
|
||||||
./npc -server=1.1.1.1:8024 -vkey=客户端的密钥
|
|
||||||
```
|
|
||||||
**注意:运行服务端后,请确保能从客户端设备上正常访问配置文件中所配置的`bridge_port`端口,telnet,netcat这类的来检查**
|
|
||||||
|
|
||||||
## 域名解析
|
|
||||||
|
|
||||||
**适用范围:** 小程序开发、微信公众号开发、产品演示
|
|
||||||
|
|
||||||
**注意:域名解析模式为http反向代理,不是dns服务器,在web上能够轻松灵活配置**
|
|
||||||
|
|
||||||
**假设场景:**
|
|
||||||
- 有一个域名proxy.com,有一台公网机器ip为1.1.1.1
|
|
||||||
- 两个内网开发站点127.0.0.1:81,127.0.0.1:82
|
|
||||||
- 想通过(http|https://)a.proxy.com访问127.0.0.1:81,通过(http|https://)b.proxy.com访问127.0.0.1:82
|
|
||||||
|
|
||||||
**使用步骤**
|
|
||||||
- 将*.proxy.com解析到公网服务器1.1.1.1
|
|
||||||
- 点击刚才创建的客户端的域名管理,添加两条规则规则:1、域名:`a.proxy.com`,内网目标:`127.0.0.1:81`,2、域名:`b.proxy.com`,内网目标:`127.0.0.1:82`
|
|
||||||
|
|
||||||
现在访问(http|https://)`a.proxy.com`,`b.proxy.com`即可成功
|
|
||||||
|
|
||||||
**https:** 如需使用https请进行相关配置,详见 [使用https](/nps_extend?id=使用https)
|
|
||||||
|
|
||||||
## tcp隧道
|
|
||||||
|
|
||||||
|
|
||||||
**适用范围:** ssh、远程桌面等tcp连接场景
|
|
||||||
|
|
||||||
**假设场景:**
|
|
||||||
想通过访问公网服务器1.1.1.1的8001端口,连接内网机器10.1.50.101的22端口,实现ssh连接
|
|
||||||
|
|
||||||
**使用步骤**
|
|
||||||
- 在刚才创建的客户端隧道管理中添加一条tcp隧道,填写监听的端口(8001)、内网目标ip和目标端口(10.1.50.101:22),保存。
|
|
||||||
- 访问公网服务器ip(1.1.1.1),填写的监听端口(8001),相当于访问内网ip(10.1.50.101):目标端口(22),例如:`ssh -p 8001 root@1.1.1.1`
|
|
||||||
|
|
||||||
## udp隧道
|
|
||||||
|
|
||||||
**适用范围:** 内网dns解析等udp连接场景
|
|
||||||
|
|
||||||
**假设场景:**
|
|
||||||
内网有一台dns(10.1.50.102:53),在非内网环境下想使用该dns,公网服务器为1.1.1.1
|
|
||||||
|
|
||||||
**使用步骤**
|
|
||||||
- 在刚才创建的客户端的隧道管理中添加一条udp隧道,填写监听的端口(53)、内网目标ip和目标端口(10.1.50.102:53),保存。
|
|
||||||
- 修改需要使用的dns地址为1.1.1.1,则相当于使用10.1.50.102作为dns服务器
|
|
||||||
|
|
||||||
## socks5代理
|
|
||||||
|
|
||||||
|
|
||||||
**适用范围:** 在外网环境下如同使用vpn一样访问内网设备或者资源
|
|
||||||
|
|
||||||
**假设场景:**
|
|
||||||
想将公网服务器1.1.1.1的8003端口作为socks5代理,达到访问内网任意设备或者资源的效果
|
|
||||||
|
|
||||||
**使用步骤**
|
|
||||||
- 在刚才创建的客户端隧道管理中添加一条socks5代理,填写监听的端口(8003),保存。
|
|
||||||
- 在外网环境的本机配置socks5代理(例如使用proxifier进行全局代理),ip为公网服务器ip(1.1.1.1),端口为填写的监听端口(8003),即可畅享内网了
|
|
||||||
|
|
||||||
**注意**
|
|
||||||
经过socks5代理,当收到socks5数据包时socket已经是accept状态。表现是扫描端口全open,建立连接后短时间关闭。若想同内网表现一致,建议远程连接一台设备。
|
|
||||||
|
|
||||||
## http正向代理
|
|
||||||
|
|
||||||
**适用范围:** 在外网环境下使用http正向代理访问内网站点
|
|
||||||
|
|
||||||
**假设场景:**
|
|
||||||
想将公网服务器1.1.1.1的8004端口作为http代理,访问内网网站
|
|
||||||
|
|
||||||
**使用步骤**
|
|
||||||
|
|
||||||
- 在刚才创建的客户端隧道管理中添加一条http代理,填写监听的端口(8004),保存。
|
|
||||||
- 在外网环境的本机配置http代理,ip为公网服务器ip(1.1.1.1),端口为填写的监听端口(8004),即可访问了
|
|
||||||
|
|
||||||
**注意:对于私密代理与p2p,除了统一配置的客户端和服务端,还需要一个客户端作为访问端提供一个端口来访问**
|
|
||||||
|
|
||||||
## 私密代理
|
|
||||||
|
|
||||||
**适用范围:** 无需占用多余的端口、安全性要求较高可以防止其他人连接的tcp服务,例如ssh。
|
|
||||||
|
|
||||||
**假设场景:**
|
|
||||||
无需新增多的端口实现访问内网服务器10.1.50.2的22端口
|
|
||||||
|
|
||||||
**使用步骤**
|
|
||||||
- 在刚才创建的客户端中添加一条私密代理,并设置唯一密钥secrettest和内网目标10.1.50.2:22
|
|
||||||
- 在需要连接ssh的机器上以执行命令
|
|
||||||
|
|
||||||
```
|
|
||||||
./npc -server=1.1.1.1:8024 -vkey=vkey -type=tcp -password=secrettest -local_type=secret
|
|
||||||
```
|
|
||||||
如需指定本地端口可加参数`-local_port=xx`,默认为2000
|
|
||||||
|
|
||||||
**注意:** password为web管理上添加的唯一密钥,具体命令可查看web管理上的命令提示
|
|
||||||
|
|
||||||
假设10.1.50.2用户名为root,现在执行`ssh -p 2000 root@127.0.0.1`即可访问ssh
|
|
||||||
|
|
||||||
|
|
||||||
## p2p服务
|
|
||||||
|
|
||||||
**适用范围:** 大流量传输场景,流量不经过公网服务器,但是由于p2p穿透和nat类型关系较大,不保证100%成功,支持大部分nat类型。[nat类型检测](/npc_extend?id=nat类型检测)
|
|
||||||
|
|
||||||
**假设场景:**
|
|
||||||
|
|
||||||
想通过访问使用端机器(访问端,也就是本机)的2000端口---->访问到内网机器 10.2.50.2的22端口
|
|
||||||
|
|
||||||
**使用步骤**
|
|
||||||
- 在`nps.conf`中设置`p2p_ip`(nps服务器ip)和`p2p_port`(nps服务器udp端口)
|
|
||||||
> 注:若 `p2p_port` 设置为6000,请在防火墙开放6000~6002(额外添加2个端口)udp端口
|
|
||||||
- 在刚才刚才创建的客户端中添加一条p2p代理,并设置唯一密钥p2pssh
|
|
||||||
- 在使用端机器(本机)执行命令
|
|
||||||
|
|
||||||
```
|
|
||||||
./npc -server=1.1.1.1:8024 -vkey=123 -password=p2pssh -target=10.2.50.2:22
|
|
||||||
```
|
|
||||||
如需指定本地端口可加参数`-local_port=xx`,默认为2000
|
|
||||||
|
|
||||||
**注意:** password为web管理上添加的唯一密钥,具体命令可查看web管理上的命令提示
|
|
||||||
|
|
||||||
假设内网机器为10.2.50.2的ssh用户名为root,现在在本机上执行`ssh -p 2000 root@127.0.0.1`即可访问机器2的ssh,如果是网站在浏览器访问127.0.0.1:2000端口即可。
|
|
20
docs/faq.md
20
docs/faq.md
@ -1,20 +0,0 @@
|
|||||||
# FAQ
|
|
||||||
|
|
||||||
- 服务端无法启动
|
|
||||||
```
|
|
||||||
服务端默认配置启用了8024,8080,80,443端口,端口冲突无法启动,请修改配置
|
|
||||||
```
|
|
||||||
- 客户端无法连接服务端
|
|
||||||
```
|
|
||||||
请检查配置文件中的所有端口是否在安全组,防火墙放行
|
|
||||||
请检查vkey是否对应
|
|
||||||
请检查版本是否对应
|
|
||||||
```
|
|
||||||
- 服务端配置文件修改无效
|
|
||||||
```
|
|
||||||
install 之后,Linux 配置文件在 /etc/nps
|
|
||||||
```
|
|
||||||
- p2p穿透失败 [p2p服务](https://ehang-io.github.io/nps/#/example?id=p2p%e6%9c%8d%e5%8a%a1)
|
|
||||||
```
|
|
||||||
双方nat类型都是Symmetric Nat一定不成功,建议先查看nat类型。请按照文档操作(标题上有超链接)
|
|
||||||
```
|
|
254
docs/feature.md
254
docs/feature.md
@ -1,254 +0,0 @@
|
|||||||
# 扩展功能
|
|
||||||
## 缓存支持
|
|
||||||
对于web站点来说,一些静态文件往往消耗更大的流量,且在内网穿透中,静态文件还需到客户端获取一次,这将导致更大的流量消耗。nps在域名解析代理中支持对静态文件进行缓存。
|
|
||||||
|
|
||||||
即假设一个站点有a.css,nps将只需从npc客户端读取一次该文件,然后把该文件的内容放在内存中,下一次将不再对npc客户端进行请求而直接返回内存中的对应内容。该功能默认是关闭的,如需开启请在`nps.conf`中设置`http_cache=true`,并设置`http_cache_length`(缓存文件的个数,消耗内存,不宜过大,0表示不限制个数)
|
|
||||||
|
|
||||||
## 数据压缩支持
|
|
||||||
|
|
||||||
由于是内网穿透,内网客户端与服务端之间的隧道存在大量的数据交换,为节省流量,加快传输速度,由此本程序支持SNNAPY形式的压缩。
|
|
||||||
|
|
||||||
|
|
||||||
- 所有模式均支持数据压缩
|
|
||||||
- 在web管理或客户端配置文件中设置
|
|
||||||
|
|
||||||
|
|
||||||
## 加密传输
|
|
||||||
|
|
||||||
如果公司内网防火墙对外网访问进行了流量识别与屏蔽,例如禁止了ssh协议等,通过设置 配置文件,将服务端与客户端之间的通信内容加密传输,将会有效防止流量被拦截。
|
|
||||||
- nps现在默认每次启动时随机生成tls证书,用于加密传输
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## 站点保护
|
|
||||||
域名代理模式所有客户端共用一个http服务端口,在知道域名后任何人都可访问,一些开发或者测试环境需要保密,所以可以设置用户名和密码,nps将通过 Http Basic Auth 来保护,访问时需要输入正确的用户名和密码。
|
|
||||||
|
|
||||||
|
|
||||||
- 在web管理或客户端配置文件中设置
|
|
||||||
|
|
||||||
## host修改
|
|
||||||
|
|
||||||
由于内网站点需要的host可能与公网域名不一致,域名代理支持host修改功能,即修改request的header中的host字段。
|
|
||||||
|
|
||||||
**使用方法:在web管理中设置**
|
|
||||||
|
|
||||||
## 自定义header
|
|
||||||
|
|
||||||
支持对header进行新增或者修改,以配合服务的需要
|
|
||||||
|
|
||||||
## 404页面配置
|
|
||||||
支持域名解析模式的自定义404页面,修改/web/static/page/error.html中内容即可,暂不支持静态文件等内容
|
|
||||||
|
|
||||||
## 流量限制
|
|
||||||
|
|
||||||
支持客户端级流量限制,当该客户端入口流量与出口流量达到设定的总量后会拒绝服务
|
|
||||||
,域名代理会返回404页面,其他代理会拒绝连接,使用该功能需要在`nps.conf`中设置`allow_flow_limit`,默认是关闭的。
|
|
||||||
|
|
||||||
## 带宽限制
|
|
||||||
|
|
||||||
支持客户端级带宽限制,带宽计算方式为入口和出口总和,权重均衡,使用该功能需要在`nps.conf`中设置`allow_rate_limit`,默认是关闭的。
|
|
||||||
|
|
||||||
## 负载均衡
|
|
||||||
本代理支持域名解析模式和tcp代理的负载均衡,在web域名添加或者编辑中内网目标分行填写多个目标即可实现轮训级别的负载均衡
|
|
||||||
|
|
||||||
## 端口白名单
|
|
||||||
为了防止服务端上的端口被滥用,可在nps.conf中配置allow_ports限制可开启的端口,忽略或者不填表示端口不受限制,格式:
|
|
||||||
|
|
||||||
```ini
|
|
||||||
allow_ports=9001-9009,10001,11000-12000
|
|
||||||
```
|
|
||||||
|
|
||||||
## 端口范围映射
|
|
||||||
当客户端以配置文件的方式启动时,可以将本地的端口进行范围映射,仅支持tcp和udp模式,例如:
|
|
||||||
|
|
||||||
```ini
|
|
||||||
[tcp]
|
|
||||||
mode=tcp
|
|
||||||
server_port=9001-9009,10001,11000-12000
|
|
||||||
target_port=8001-8009,10002,13000-14000
|
|
||||||
```
|
|
||||||
|
|
||||||
逗号分隔,可单个或者范围,注意上下端口的对应关系,无法一一对应将不能成功
|
|
||||||
## 端口范围映射到其他机器
|
|
||||||
```ini
|
|
||||||
[tcp]
|
|
||||||
mode=tcp
|
|
||||||
server_port=9001-9009,10001,11000-12000
|
|
||||||
target_port=8001-8009,10002,13000-14000
|
|
||||||
target_ip=10.1.50.2
|
|
||||||
```
|
|
||||||
填写target_ip后则表示映射的该地址机器的端口,忽略则便是映射本地127.0.0.1,仅范围映射时有效
|
|
||||||
|
|
||||||
## KCP协议支持
|
|
||||||
|
|
||||||
在网络质量非常好的情况下,例如专线,内网,可以开启略微降低延迟。如需使用可在nps.conf中修改`bridge_type`为kcp
|
|
||||||
,设置后本代理将开启udp端口(`bridge_port`)
|
|
||||||
|
|
||||||
注意:当服务端为kcp时,客户端连接时也需要使用相同配置,无配置文件模式加上参数type=kcp,配置文件模式在配置文件中设置tp=kcp
|
|
||||||
|
|
||||||
## 域名泛解析
|
|
||||||
支持域名泛解析,例如将host设置为*.proxy.com,a.proxy.com、b.proxy.com等都将解析到同一目标,在web管理中或客户端配置文件中将host设置为此格式即可。
|
|
||||||
|
|
||||||
## URL路由
|
|
||||||
本代理支持根据URL将同一域名转发到不同的内网服务器,可在web中或客户端配置文件中设置,此参数也可忽略,例如在客户端配置文件中
|
|
||||||
|
|
||||||
```ini
|
|
||||||
[web1]
|
|
||||||
host=a.proxy.com
|
|
||||||
target_addr=127.0.0.1:7001
|
|
||||||
location=/test
|
|
||||||
[web2]
|
|
||||||
host=a.proxy.com
|
|
||||||
target_addr=127.0.0.1:7002
|
|
||||||
location=/static
|
|
||||||
```
|
|
||||||
对于`a.proxy.com/test`将转发到`web1`,对于`a.proxy.com/static`将转发到`web2`
|
|
||||||
|
|
||||||
## 限制ip访问
|
|
||||||
如果将一些危险性高的端口例如ssh端口暴露在公网上,可能会带来一些风险,本代理支持限制ip访问。
|
|
||||||
|
|
||||||
**使用方法:** 在配置文件nps.conf中设置`ip_limit`=true,设置后仅通过注册的ip方可访问。
|
|
||||||
|
|
||||||
**ip注册**:
|
|
||||||
|
|
||||||
**方式一:**
|
|
||||||
在需要访问的机器上,运行客户端
|
|
||||||
|
|
||||||
```
|
|
||||||
./npc register -server=ip:port -vkey=公钥或客户端密钥 time=2
|
|
||||||
```
|
|
||||||
|
|
||||||
time为有效小时数,例如time=2,在当前时间后的两小时内,本机公网ip都可以访问nps代理.
|
|
||||||
|
|
||||||
**方式二:**
|
|
||||||
此外nps的web登陆也可提供验证的功能,成功登陆nps web admin后将自动为登陆的ip注册两小时的允许访问权限。
|
|
||||||
|
|
||||||
|
|
||||||
**注意:** 本机公网ip并不是一成不变的,请自行注意有效期的设置,同时同一网络下,多人也可能是在公用同一个公网ip。
|
|
||||||
## 客户端最大连接数
|
|
||||||
为防止恶意大量长连接,影响服务端程序的稳定性,可以在web或客户端配置文件中为每个客户端设置最大连接数。该功能针对`socks5`、`http正向代理`、`域名代理`、`tcp代理`、`udp代理`、`私密代理`生效,使用该功能需要在`nps.conf`中设置`allow_connection_num_limit=true`,默认是关闭的。
|
|
||||||
|
|
||||||
## 客户端最大隧道数限制
|
|
||||||
nps支持对客户端的隧道数量进行限制,该功能默认是关闭的,如需开启,请在`nps.conf`中设置`allow_tunnel_num_limit=true`。
|
|
||||||
## 端口复用
|
|
||||||
在一些严格的网络环境中,对端口的个数等限制较大,nps支持强大端口复用功能。将`bridge_port`、 `http_proxy_port`、 `https_proxy_port` 、`web_port`都设置为同一端口,也能正常使用。
|
|
||||||
|
|
||||||
- 使用时将需要复用的端口设置为与`bridge_port`一致即可,将自动识别。
|
|
||||||
- 如需将web管理的端口也复用,需要配置`web_host`也就是一个二级域名以便区分
|
|
||||||
|
|
||||||
## 多路复用
|
|
||||||
|
|
||||||
nps主要通信默认基于多路复用,无需开启。
|
|
||||||
|
|
||||||
多路复用基于TCP滑动窗口原理设计,动态计算延迟以及带宽来算出应该往网络管道中打入的流量。
|
|
||||||
由于主要通信大多采用TCP协议,并无法探测其实时丢包情况,对于产生丢包重传的情况,采用较大的宽容度,
|
|
||||||
5分钟的等待时间,超时将会关闭当前隧道连接并重新建立,这将会抛弃当前所有的连接。
|
|
||||||
在Linux上,可以通过调节内核参数来适应不同应用场景。
|
|
||||||
|
|
||||||
对于需求大带宽又有一定的丢包的场景,可以保持默认参数不变,尽可能少抛弃连接
|
|
||||||
高并发下可根据[Linux系统限制](## Linux系统限制) 调整
|
|
||||||
|
|
||||||
对于延迟敏感而又有一定丢包的场景,可以适当调整TCP重传次数
|
|
||||||
`tcp_syn_retries`, `tcp_retries1`, `tcp_retries2`
|
|
||||||
高并发同上
|
|
||||||
nps会在系统主动关闭连接的时候拿到报错,进而重新建立隧道连接
|
|
||||||
|
|
||||||
## 环境变量渲染
|
|
||||||
npc支持环境变量渲染以适应在某些特殊场景下的要求。
|
|
||||||
|
|
||||||
**在无配置文件启动模式下:**
|
|
||||||
设置环境变量
|
|
||||||
```
|
|
||||||
export NPC_SERVER_ADDR=1.1.1.1:8024
|
|
||||||
export NPC_SERVER_VKEY=xxxxx
|
|
||||||
```
|
|
||||||
直接执行./npc即可运行
|
|
||||||
|
|
||||||
**在配置文件启动模式下:**
|
|
||||||
```ini
|
|
||||||
[common]
|
|
||||||
server_addr={{.NPC_SERVER_ADDR}}
|
|
||||||
conn_type=tcp
|
|
||||||
vkey={{.NPC_SERVER_VKEY}}
|
|
||||||
auto_reconnection=true
|
|
||||||
[web]
|
|
||||||
host={{.NPC_WEB_HOST}}
|
|
||||||
target_addr={{.NPC_WEB_TARGET}}
|
|
||||||
```
|
|
||||||
在配置文件中填入相应的环境变量名称,npc将自动进行渲染配置文件替换环境变量
|
|
||||||
|
|
||||||
## 健康检查
|
|
||||||
|
|
||||||
当客户端以配置文件模式启动时,支持多节点的健康检查。配置示例如下
|
|
||||||
|
|
||||||
```ini
|
|
||||||
[health_check_test1]
|
|
||||||
health_check_timeout=1
|
|
||||||
health_check_max_failed=3
|
|
||||||
health_check_interval=1
|
|
||||||
health_http_url=/
|
|
||||||
health_check_type=http
|
|
||||||
health_check_target=127.0.0.1:8083,127.0.0.1:8082
|
|
||||||
|
|
||||||
[health_check_test2]
|
|
||||||
health_check_timeout=1
|
|
||||||
health_check_max_failed=3
|
|
||||||
health_check_interval=1
|
|
||||||
health_check_type=tcp
|
|
||||||
health_check_target=127.0.0.1:8083,127.0.0.1:8082
|
|
||||||
```
|
|
||||||
**health关键词必须在开头存在**
|
|
||||||
|
|
||||||
第一种是http模式,也就是以get的方式请求目标+url,返回状态码为200表示成功
|
|
||||||
|
|
||||||
第一种是tcp模式,也就是以tcp的方式与目标建立连接,能成功建立连接表示成功
|
|
||||||
|
|
||||||
如果失败次数超过`health_check_max_failed`,nps则会移除该npc下的所有该目标,如果失败后目标重新上线,nps将自动将目标重新加入。
|
|
||||||
|
|
||||||
项 | 含义
|
|
||||||
---|---
|
|
||||||
health_check_timeout | 健康检查超时时间
|
|
||||||
health_check_max_failed | 健康检查允许失败次数
|
|
||||||
health_check_interval | 健康检查间隔
|
|
||||||
health_check_type | 健康检查类型
|
|
||||||
health_check_target | 健康检查目标,多个以逗号(,)分隔
|
|
||||||
health_check_type | 健康检查类型
|
|
||||||
health_http_url | 健康检查url,仅http模式适用
|
|
||||||
|
|
||||||
## 日志输出
|
|
||||||
|
|
||||||
日志输出级别
|
|
||||||
|
|
||||||
**对于npc:**
|
|
||||||
```
|
|
||||||
-log_level=0~7 -log_path=npc.log
|
|
||||||
```
|
|
||||||
```
|
|
||||||
LevelEmergency->0 LevelAlert->1
|
|
||||||
|
|
||||||
LevelCritical->2 LevelError->3
|
|
||||||
|
|
||||||
LevelWarning->4 LevelNotice->5
|
|
||||||
|
|
||||||
LevelInformational->6 LevelDebug->7
|
|
||||||
```
|
|
||||||
默认为全输出,级别为0到7
|
|
||||||
|
|
||||||
**对于nps:**
|
|
||||||
|
|
||||||
在`nps.conf`中设置相关配置即可
|
|
||||||
|
|
||||||
## pprof性能分析与调试
|
|
||||||
|
|
||||||
可在服务端与客户端配置中开启pprof端口,用于性能分析与调试,注释或留空相应参数为关闭。
|
|
||||||
|
|
||||||
默认为关闭状态
|
|
||||||
|
|
||||||
## 自定义客户端超时检测断开时间
|
|
||||||
|
|
||||||
客户端与服务端间会间隔5s相互发送延迟测量包,这个时间间隔不可修改。
|
|
||||||
可修改延迟测量包丢包的次数,默认为60也就是5分钟都收不到一个延迟测量回包,则会断开客户端连接。
|
|
||||||
值得注意的是需要客户端的socket关闭,才会进行重连,也就是当客户端无法收到服务端的fin包时,只有客户端自行关闭socket才行。
|
|
||||||
也就是假如服务端设置为较低值,而客户端设置较高值,而此时服务端断开连接而客户端无法收到服务端的fin包,客户端也会继续等着直到触发客户端的超时设置。
|
|
||||||
|
|
||||||
在`nps.conf`或`npc.conf`中设置`disconnect_timeout`即可,客户端还可附带`-disconnect_timeout=60`参数启动
|
|
@ -1,43 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<title>Document</title>
|
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"/>
|
|
||||||
<meta name="description" content="Description">
|
|
||||||
<meta name="viewport"
|
|
||||||
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
|
|
||||||
<link rel="stylesheet" href="//unpkg.com/docsify/lib/themes/vue.css">
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="app"></div>
|
|
||||||
<script src="//unpkg.com/docsify-edit-on-github/index.js"></script>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
|
|
||||||
window.$docsify = {
|
|
||||||
name: '',
|
|
||||||
repo: '',
|
|
||||||
loadSidebar: true,
|
|
||||||
coverpage: true,
|
|
||||||
loadNavbar: true,
|
|
||||||
subMaxLevel: 2,
|
|
||||||
maxLevel: 4,
|
|
||||||
search: {
|
|
||||||
noData: "没有结果",
|
|
||||||
paths: 'auto',
|
|
||||||
placeholder: "搜索",
|
|
||||||
hideOtherSidebarContent: true, // whether or not to hide other sidebar content
|
|
||||||
},
|
|
||||||
plugins: [
|
|
||||||
EditOnGithubPlugin.create("https://github.com/ehang-io/nps/tree/master/docs/", "", "在github上编辑"),
|
|
||||||
]
|
|
||||||
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
<script src="//unpkg.com/docsify/lib/docsify.min.js"></script>
|
|
||||||
<script src="//unpkg.com/docsify/lib/plugins/search.min.js"></script>
|
|
||||||
<script src="//unpkg.com/docsify-copy-code"></script>
|
|
||||||
|
|
||||||
</body>
|
|
||||||
</html>
|
|
@ -1,18 +0,0 @@
|
|||||||
# 安装
|
|
||||||
## 安装包安装
|
|
||||||
[releases](https://github.com/ehang-io/nps/releases)
|
|
||||||
|
|
||||||
下载对应的系统版本即可,服务端和客户端是单独的
|
|
||||||
|
|
||||||
## 源码安装
|
|
||||||
- 安装源码
|
|
||||||
```go get -u ehang.io/nps```
|
|
||||||
- 编译
|
|
||||||
|
|
||||||
服务端```go build cmd/nps/nps.go```
|
|
||||||
|
|
||||||
客户端```go build cmd/npc/npc.go```
|
|
||||||
|
|
||||||
## docker安装
|
|
||||||
> [server](https://hub.docker.com/r/ffdfgdfg/nps)
|
|
||||||
> [client](https://hub.docker.com/r/ffdfgdfg/npc)
|
|
@ -1,4 +0,0 @@
|
|||||||

|
|
||||||
# 介绍
|
|
||||||
|
|
||||||
可在网页上配置和管理各个tcp、udp隧道、内网站点代理,http、https解析等,功能强大,操作方便。
|
|
BIN
docs/logo.png
BIN
docs/logo.png
Binary file not shown.
Before Width: | Height: | Size: 1.4 KiB |
@ -1 +0,0 @@
|
|||||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1576165662444" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="50156" xmlns:xlink="http://www.w3.org/1999/xlink" width="48" height="48"><defs><style type="text/css"></style></defs><path d="M414.764 498.138c-4.094-8.188-13-12.844-22.094-11.562L181.58 516.73a21.496 21.496 0 0 0-12.062 6.032L48.926 643.4c-8.344 8.344-8.344 21.842 0 30.154l90.436 90.466c8.344 8.312 21.844 8.312 30.156 0l241.246-241.26a21.344 21.344 0 0 0 4-24.622zM507.262 842.428l30.156-211.09c1.312-9.094-3.376-17.968-11.562-22.094a21.34 21.34 0 0 0-24.624 4L259.984 854.49c-8.312 8.312-8.312 21.812 0 30.156l90.468 90.464c8.344 8.312 21.842 8.312 30.156 0l120.624-120.622a21.214 21.214 0 0 0 6.03-12.06z" fill="#DA4453" p-id="50157"></path><path d="M732.444 186.238a21.254 21.254 0 0 0-14.75-15.156l-93.778-26.876a21.288 21.288 0 0 0-20.938 5.438l-87.188 87.154a21.266 21.266 0 0 0-5.656 19.968 21.088 21.088 0 0 0 5.656 10.188 21.33 21.33 0 0 0 8.344 5.156l90.468 30.156a21.27 21.27 0 0 0 21.812-5.156l90.464-90.468a21.252 21.252 0 0 0 5.566-20.404zM879.786 400.078l-26.842-93.75a21.348 21.348 0 0 0-15.156-14.78 21.388 21.388 0 0 0-20.438 5.562l-90.468 90.466a21.348 21.348 0 0 0-5.156 21.812l30.156 90.466a21.33 21.33 0 0 0 5.156 8.344 21.4 21.4 0 0 0 10.188 5.688 21.356 21.356 0 0 0 19.968-5.688l87.186-87.156a21.39 21.39 0 0 0 5.406-20.964z" fill="#434A54" p-id="50158"></path><path d="M997.284 138.206c30.312-61.56 34.876-103.592 13.5-124.966-21.376-21.374-63.438-16.842-124.998 13.5-47.06 23.188-97.592 58.28-128.748 89.436L6.27 866.99c-4 4-6.25 9.406-6.25 15.062s2.25 11.094 6.25 15.094l120.624 120.59c8.312 8.344 21.812 8.344 30.156 0l750.768-750.782c31.154-31.156 66.278-81.686 89.466-128.748z" fill="#E6E9ED" p-id="50159"></path><path d="M907.816 266.954c31.154-31.156 66.28-81.686 89.466-128.748 30.312-61.56 34.876-103.592 13.5-124.966-21.376-21.374-63.438-16.842-124.998 13.5-47.06 23.188-97.592 58.28-128.748 89.436l150.78 150.778z" fill="#ED5564" p-id="50160"></path><path d="M157.048 1017.736l15.062-15.062-150.778-150.778-15.062 15.094c-4 4-6.25 9.406-6.25 15.062s2.25 11.094 6.25 15.094l120.624 120.59c8.312 8.344 21.81 8.344 30.154 0z" fill="#FFCE54" p-id="50161"></path><path d="M81.662 972.546l-30.156-30.156 30.156-30.154L111.814 942.39z" fill="#F6BB42" p-id="50162"></path><path d="M199.672 824.334c-8.312-8.344-8.312-21.844 0-30.156l241.246-241.246c8.344-8.312 21.844-8.312 30.156 0 8.344 8.344 8.344 21.844 0 30.156L229.828 824.334c-8.312 8.312-21.812 8.312-30.156 0z" fill="#ED5564" p-id="50163"></path><path d="M787.194 236.798c-8.312-8.312-21.812-8.312-30.156 0l-120.622 120.624c-8.312 8.344-8.312 21.844 0 30.156 8.342 8.344 21.842 8.344 30.154 0l120.624-120.624c8.344-8.312 8.344-21.812 0-30.156z" fill="#656D78" p-id="50164"></path><path d="M997.284 138.206c30.312-61.56 34.876-103.592 13.5-124.966a40.728 40.728 0 0 0-8.562-6.562c13.376 23.156 6.688 62.25-20.032 116.466-23.188 47.062-58.312 97.592-89.436 128.748L141.954 1002.674c-8.312 8.312-21.812 8.312-30.156 0l-60.312-60.31-45.216-45.248v0.032l120.624 120.59c8.312 8.344 21.812 8.344 30.156 0l750.768-750.782c31.154-31.158 66.278-81.688 89.466-128.75z" fill="#FFFFFF" opacity=".2" p-id="50165"></path></svg>
|
|
Before Width: | Height: | Size: 3.3 KiB |
@ -1,36 +0,0 @@
|
|||||||
# 增强功能
|
|
||||||
## nat类型检测
|
|
||||||
```
|
|
||||||
./npc nat -stun_addr=stun.stunprotocol.org:3478
|
|
||||||
```
|
|
||||||
如果p2p双方都是Symmetric Nat,肯定不能成功,其他组合都有较大成功率。`stun_addr`可以指定stun服务器地址。
|
|
||||||
## 状态检查
|
|
||||||
```
|
|
||||||
./npc status -config=npc配置文件路径
|
|
||||||
```
|
|
||||||
## 重载配置文件
|
|
||||||
```
|
|
||||||
./npc restart -config=npc配置文件路径
|
|
||||||
```
|
|
||||||
|
|
||||||
## 通过代理连接nps
|
|
||||||
有时候运行npc的内网机器无法直接访问外网,此时可以可以通过socks5代理连接nps
|
|
||||||
|
|
||||||
对于配置文件方式启动,设置
|
|
||||||
```ini
|
|
||||||
[common]
|
|
||||||
proxy_url=socks5://111:222@127.0.0.1:8024
|
|
||||||
```
|
|
||||||
对于无配置文件模式,加上参数
|
|
||||||
|
|
||||||
```
|
|
||||||
-proxy=socks5://111:222@127.0.0.1:8024
|
|
||||||
```
|
|
||||||
支持socks5和http两种模式
|
|
||||||
|
|
||||||
即socks5://username:password@ip:port
|
|
||||||
|
|
||||||
或http://username:password@ip:port
|
|
||||||
|
|
||||||
## 群晖支持
|
|
||||||
可在releases中下载spk群晖套件,例如`npc_x64-6.1_0.19.0-1.spk`
|
|
@ -1,24 +0,0 @@
|
|||||||
# npc sdk文档
|
|
||||||
|
|
||||||
```
|
|
||||||
命令行模式启动客户端
|
|
||||||
从v0.26.10开始,此函数会阻塞,直到客户端退出返回,请自行管理是否重连
|
|
||||||
p0->连接地址
|
|
||||||
p1->vkey
|
|
||||||
p2->连接类型(tcp or udp)
|
|
||||||
p3->连接代理
|
|
||||||
|
|
||||||
extern GoInt StartClientByVerifyKey(char* p0, char* p1, char* p2, char* p3);
|
|
||||||
|
|
||||||
查看当前启动的客户端状态,在线为1,离线为0
|
|
||||||
extern GoInt GetClientStatus();
|
|
||||||
|
|
||||||
关闭客户端
|
|
||||||
extern void CloseClient();
|
|
||||||
|
|
||||||
获取当前客户端版本
|
|
||||||
extern char* Version();
|
|
||||||
|
|
||||||
获取日志,实时更新
|
|
||||||
extern char* Logs();
|
|
||||||
```
|
|
@ -1,107 +0,0 @@
|
|||||||
# 增强功能
|
|
||||||
## 使用https
|
|
||||||
|
|
||||||
**方式一:** 类似于nginx实现https的处理
|
|
||||||
|
|
||||||
在配置文件中将https_proxy_port设置为443或者其他你想配置的端口,将`https_just_proxy`设置为false,nps 重启后,在web管理界面,域名新增或修改界面中修改域名证书和密钥。
|
|
||||||
|
|
||||||
**此外:** 可以在`nps.conf`中设置一个默认的https配置,当遇到未在web中设置https证书的域名解析时,将自动使用默认证书,另还有一种情况就是对于某些请求的clienthello不携带sni扩展信息,nps也将自动使用默认证书
|
|
||||||
|
|
||||||
|
|
||||||
**方式二:** 在内网对应服务器上设置https
|
|
||||||
|
|
||||||
在`nps.conf`中将`https_just_proxy`设置为true,并且打开`https_proxy_port`端口,然后nps将直接转发https请求到内网服务器上,由内网服务器进行https处理
|
|
||||||
|
|
||||||
## 与nginx配合
|
|
||||||
|
|
||||||
有时候我们还需要在云服务器上运行nginx来保证静态文件缓存等,本代理可和nginx配合使用,在配置文件中将httpProxyPort设置为非80端口,并在nginx中配置代理,例如httpProxyPort为8010时
|
|
||||||
```
|
|
||||||
server {
|
|
||||||
listen 80;
|
|
||||||
server_name *.proxy.com;
|
|
||||||
location / {
|
|
||||||
proxy_set_header Host $http_host;
|
|
||||||
proxy_pass http://127.0.0.1:8010;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
如需使用https也可在nginx监听443端口并配置ssl,并将本代理的httpsProxyPort设置为空关闭https即可,例如httpProxyPort为8020时
|
|
||||||
|
|
||||||
```
|
|
||||||
server {
|
|
||||||
listen 443;
|
|
||||||
server_name *.proxy.com;
|
|
||||||
ssl on;
|
|
||||||
ssl_certificate certificate.crt;
|
|
||||||
ssl_certificate_key private.key;
|
|
||||||
ssl_session_timeout 5m;
|
|
||||||
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
|
|
||||||
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
|
|
||||||
ssl_prefer_server_ciphers on;
|
|
||||||
location / {
|
|
||||||
proxy_set_header Host $http_host;
|
|
||||||
proxy_pass http://127.0.0.1:8020;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
## web管理使用https
|
|
||||||
如果web管理需要使用https,可以在配置文件`nps.conf`中设置`web_open_ssl=true`,并配置`web_cert_file`和`web_key_file`
|
|
||||||
## web使用Caddy代理
|
|
||||||
|
|
||||||
如果将web配置到Caddy代理,实现子路径访问nps,可以这样配置.
|
|
||||||
|
|
||||||
假设我们想通过 `http://caddy_ip:caddy_port/nps` 来访问后台, Caddyfile 这样配置:
|
|
||||||
|
|
||||||
```Caddyfile
|
|
||||||
caddy_ip:caddy_port/nps {
|
|
||||||
##server_ip 为 nps 服务器IP
|
|
||||||
##web_port 为 nps 后台端口
|
|
||||||
proxy / http://server_ip:web_port/nps {
|
|
||||||
transparent
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
nps.conf 修改 `web_base_url` 为 `/nps` 即可
|
|
||||||
```
|
|
||||||
web_base_url=/nps
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
## 关闭代理
|
|
||||||
|
|
||||||
如需关闭http代理可在配置文件中将http_proxy_port设置为空,如需关闭https代理可在配置文件中将https_proxy_port设置为空。
|
|
||||||
|
|
||||||
## 流量数据持久化
|
|
||||||
服务端支持将流量数据持久化,默认情况下是关闭的,如果有需求可以设置`nps.conf`中的`flow_store_interval`参数,单位为分钟
|
|
||||||
|
|
||||||
**注意:** nps不会持久化通过公钥连接的客户端
|
|
||||||
## 系统信息显示
|
|
||||||
nps服务端支持在web上显示和统计服务器的相关信息,但默认一些统计图表是关闭的,如需开启请在`nps.conf`中设置`system_info_display=true`
|
|
||||||
|
|
||||||
## 自定义客户端连接密钥
|
|
||||||
web上可以自定义客户端连接的密钥,但是必须具有唯一性
|
|
||||||
## 关闭公钥访问
|
|
||||||
可以将`nps.conf`中的`public_vkey`设置为空或者删除
|
|
||||||
|
|
||||||
## 关闭web管理
|
|
||||||
可以将`nps.conf`中的`web_port`设置为空或者删除
|
|
||||||
|
|
||||||
## 服务端多用户登陆
|
|
||||||
如果将`nps.conf`中的`allow_user_login`设置为true,服务端web将支持多用户登陆,登陆用户名为user,默认密码为每个客户端的验证密钥,登陆后可以进入客户端编辑修改web登陆的用户名和密码,默认该功能是关闭的。
|
|
||||||
|
|
||||||
## 用户注册功能
|
|
||||||
nps服务端支持用户注册功能,可将`nps.conf`中的`allow_user_register`设置为true,开启后登陆页将会有有注册功能,
|
|
||||||
|
|
||||||
## 监听指定ip
|
|
||||||
|
|
||||||
nps支持每个隧道监听不同的服务端端口,在`nps.conf`中设置`allow_multi_ip=true`后,可在web中控制,或者npc配置文件中(可忽略,默认为0.0.0.0)
|
|
||||||
```ini
|
|
||||||
server_ip=xxx
|
|
||||||
```
|
|
||||||
## 代理到服务端本地
|
|
||||||
在使用nps监听80或者443端口时,默认是将所有的请求都会转发到内网上,但有时候我们的nps服务器的上一些服务也需要使用这两个端口,nps提供类似于`nginx` `proxy_pass` 的功能,支持将代理到服务器本地,该功能支持域名解析,tcp、udp隧道,默认关闭。
|
|
||||||
|
|
||||||
**即:** 假设在nps的vps服务器上有一个服务使用5000端口,这时候nps占用了80端口和443,我们想能使用一个域名通过http(s)访问到5000的服务。
|
|
||||||
|
|
||||||
**使用方式:** 在`nps.conf`中设置`allow_local_proxy=true`,然后在web上设置想转发的隧道或者域名然后选择转发到本地选项即可成功。
|
|
@ -1,47 +0,0 @@
|
|||||||
# 使用
|
|
||||||
**提示:使用web模式时,服务端执行文件必须在项目根目录,否则无法正确加载配置文件**
|
|
||||||
|
|
||||||
## web管理
|
|
||||||
|
|
||||||
进入web界面,公网ip:web界面端口(默认8080),密码默认为123
|
|
||||||
|
|
||||||
进入web管理界面,有详细的说明
|
|
||||||
|
|
||||||
## 服务端配置文件重载
|
|
||||||
对于linux、darwin
|
|
||||||
```shell
|
|
||||||
sudo nps reload
|
|
||||||
```
|
|
||||||
对于windows
|
|
||||||
```shell
|
|
||||||
nps.exe reload
|
|
||||||
```
|
|
||||||
**说明:** 仅支持部分配置重载,例如`allow_user_login` `auth_crypt_key` `auth_key` `web_username` `web_password` 等,未来将支持更多
|
|
||||||
|
|
||||||
|
|
||||||
## 服务端停止或重启
|
|
||||||
对于linux、darwin
|
|
||||||
```shell
|
|
||||||
sudo nps stop|restart
|
|
||||||
```
|
|
||||||
对于windows
|
|
||||||
```shell
|
|
||||||
nps.exe stop|restart
|
|
||||||
```
|
|
||||||
## 服务端更新
|
|
||||||
请首先执行 `sudo nps stop` 或者 `nps.exe stop` 停止运行,然后
|
|
||||||
|
|
||||||
对于linux
|
|
||||||
```shell
|
|
||||||
sudo nps-update update
|
|
||||||
```
|
|
||||||
对于windows
|
|
||||||
```shell
|
|
||||||
nps-update.exe update
|
|
||||||
```
|
|
||||||
|
|
||||||
更新完成后,执行执行 `sudo nps start` 或者 `nps.exe start` 重新运行即可完成升级
|
|
||||||
|
|
||||||
如果无法更新成功,可以直接自行下载releases压缩包然后覆盖原有的nps二进制文件和web目录
|
|
||||||
|
|
||||||
注意:`nps install` 之后的 nps 不在原位置,请使用 `whereis nps` 查找具体目录覆盖 nps 二进制文件
|
|
42
docs/run.md
42
docs/run.md
@ -1,42 +0,0 @@
|
|||||||
# 启动
|
|
||||||
## 服务端
|
|
||||||
下载完服务器压缩包后,解压,然后进入解压后的文件夹
|
|
||||||
|
|
||||||
- 执行安装命令
|
|
||||||
|
|
||||||
对于linux|darwin ```sudo ./nps install```
|
|
||||||
|
|
||||||
对于windows,管理员身份运行cmd,进入安装目录 ```nps.exe install```
|
|
||||||
|
|
||||||
- 启动
|
|
||||||
|
|
||||||
对于linux|darwin ```sudo nps start```
|
|
||||||
|
|
||||||
对于windows,管理员身份运行cmd,进入程序目录 ```nps.exe start```
|
|
||||||
|
|
||||||
```安装后windows配置文件位于 C:\Program Files\nps,linux和darwin位于/etc/nps```
|
|
||||||
|
|
||||||
停止和重启可用,stop和restart
|
|
||||||
|
|
||||||
**如果发现没有启动成功,可以使用`nps(.exe) stop`,然后运行`nps.(exe)`运行调试,或查看日志**(Windows日志文件位于当前运行目录下,linux和darwin位于/var/log/nps.log)
|
|
||||||
- 访问服务端ip:web服务端口(默认为8080)
|
|
||||||
- 使用用户名和密码登陆(默认admin/123,正式使用一定要更改)
|
|
||||||
- 创建客户端
|
|
||||||
|
|
||||||
## 客户端
|
|
||||||
- 下载客户端安装包并解压,进入到解压目录
|
|
||||||
- 点击web管理中客户端前的+号,复制启动命令
|
|
||||||
- 执行启动命令,linux直接执行即可,windows将./npc换成npc.exe用**cmd执行**
|
|
||||||
|
|
||||||
如果使用`powershell`运行,**请将ip括起来!**
|
|
||||||
|
|
||||||
如果需要注册到系统服务可查看[注册到系统服务](/use?id=注册到系统服务)
|
|
||||||
|
|
||||||
## 版本检查
|
|
||||||
- 对客户端以及服务的均可以使用参数`-version`打印版本
|
|
||||||
- `nps -version`或`./nps -version`
|
|
||||||
- `npc -version`或`./npc -version`
|
|
||||||
|
|
||||||
## 配置
|
|
||||||
- 客户端连接后,在web中配置对应穿透服务即可
|
|
||||||
- 可以查看[使用示例](/example)
|
|
@ -1,24 +0,0 @@
|
|||||||
# 服务端配置文件
|
|
||||||
- /etc/nps/conf/nps.conf
|
|
||||||
|
|
||||||
名称 | 含义
|
|
||||||
---|---
|
|
||||||
web_port | web管理端口
|
|
||||||
web_password | web界面管理密码
|
|
||||||
web_username | web界面管理账号
|
|
||||||
web_base_url | web管理主路径,用于将web管理置于代理子路径后面
|
|
||||||
bridge_port | 服务端客户端通信端口
|
|
||||||
https_proxy_port | 域名代理https代理监听端口
|
|
||||||
http_proxy_port | 域名代理http代理监听端口
|
|
||||||
auth_key|web api密钥
|
|
||||||
bridge_type|客户端与服务端连接方式kcp或tcp
|
|
||||||
public_vkey|客户端以配置文件模式启动时的密钥,设置为空表示关闭客户端配置文件连接模式
|
|
||||||
ip_limit|是否限制ip访问,true或false或忽略
|
|
||||||
flow_store_interval|服务端流量数据持久化间隔,单位分钟,忽略表示不持久化
|
|
||||||
log_level|日志输出级别
|
|
||||||
auth_crypt_key | 获取服务端authKey时的aes加密密钥,16位
|
|
||||||
p2p_ip| 服务端Ip,使用p2p模式必填
|
|
||||||
p2p_port|p2p模式开启的udp端口
|
|
||||||
pprof_ip|debug pprof 服务端ip
|
|
||||||
pprof_port|debug pprof 端口
|
|
||||||
disconnect_timeout|客户端连接超时,单位 5s,默认值 60,即 300s = 5mins
|
|
@ -1,5 +0,0 @@
|
|||||||
Thanks [jetbrains](https://www.jetbrains.com/?from=nps) for providing development tools for nps
|
|
||||||
|
|
||||||
<html>
|
|
||||||
<img src="https://ftp.bmp.ovh/imgs/2019/12/6435398b0c7402b1.png" width="300" align=center />
|
|
||||||
</html>
|
|
225
docs/use.md
225
docs/use.md
@ -1,225 +0,0 @@
|
|||||||
# 基本使用
|
|
||||||
## 无配置文件模式
|
|
||||||
此模式的各种配置在服务端web管理中完成,客户端除运行一条命令外无需任何其他设置
|
|
||||||
```
|
|
||||||
./npc -server=ip:port -vkey=web界面中显示的密钥
|
|
||||||
```
|
|
||||||
## 注册到系统服务(开机启动、守护进程)
|
|
||||||
对于linux、darwin
|
|
||||||
- 注册:`sudo ./npc install 其他参数(例如-server=xx -vkey=xx或者-config=xxx)`
|
|
||||||
- 启动:`sudo npc start`
|
|
||||||
- 停止:`sudo npc stop`
|
|
||||||
- 如果需要更换命令内容需要先卸载`./npc uninstall`,再重新注册
|
|
||||||
|
|
||||||
对于windows,使用管理员身份运行cmd
|
|
||||||
|
|
||||||
- 注册:`npc.exe install 其他参数(例如-server=xx -vkey=xx或者-config=xxx)`
|
|
||||||
- 启动:`npc.exe start`
|
|
||||||
- 停止:`npc.exe stop`
|
|
||||||
- 如果需要更换命令内容需要先卸载`npc.exe uninstall`,再重新注册
|
|
||||||
- 如果需要当客户端退出时自动重启客户端,请按照如图所示配置
|
|
||||||

|
|
||||||
|
|
||||||
注册到服务后,日志文件windows位于当前目录下,linux和darwin位于/var/log/npc.log
|
|
||||||
|
|
||||||
## 客户端更新
|
|
||||||
首先进入到对于的客户端二进制文件目录
|
|
||||||
|
|
||||||
请首先执行`sudo npc stop`或者`npc.exe stop`停止运行,然后
|
|
||||||
|
|
||||||
对于linux
|
|
||||||
```shell
|
|
||||||
sudo npc-update update
|
|
||||||
```
|
|
||||||
对于windows
|
|
||||||
```shell
|
|
||||||
npc-update.exe update
|
|
||||||
```
|
|
||||||
|
|
||||||
更新完成后,执行执行`sudo npc start`或者`npc.exe start`重新运行即可完成升级
|
|
||||||
|
|
||||||
如果无法更新成功,可以直接自行下载releases压缩包然后覆盖原有的npc二进制文件
|
|
||||||
|
|
||||||
## 配置文件模式
|
|
||||||
此模式使用nps的公钥或者客户端私钥验证,各种配置在客户端完成,同时服务端web也可以进行管理
|
|
||||||
```
|
|
||||||
./npc -config=npc配置文件路径
|
|
||||||
```
|
|
||||||
## 配置文件说明
|
|
||||||
[示例配置文件](https://github.com/ehang-io/nps/tree/master/conf/npc.conf)
|
|
||||||
#### 全局配置
|
|
||||||
```ini
|
|
||||||
[common]
|
|
||||||
server_addr=1.1.1.1:8024
|
|
||||||
conn_type=tcp
|
|
||||||
vkey=123
|
|
||||||
username=111
|
|
||||||
password=222
|
|
||||||
compress=true
|
|
||||||
crypt=true
|
|
||||||
rate_limit=10000
|
|
||||||
flow_limit=100
|
|
||||||
remark=test
|
|
||||||
max_conn=10
|
|
||||||
#pprof_addr=0.0.0.0:9999
|
|
||||||
```
|
|
||||||
项 | 含义
|
|
||||||
---|---
|
|
||||||
server_addr | 服务端ip/域名:port
|
|
||||||
conn_type | 与服务端通信模式(tcp或kcp)
|
|
||||||
vkey|服务端配置文件中的密钥(非web)
|
|
||||||
username|socks5或http(s)密码保护用户名(可忽略)
|
|
||||||
password|socks5或http(s)密码保护密码(可忽略)
|
|
||||||
compress|是否压缩传输(true或false或忽略)
|
|
||||||
crypt|是否加密传输(true或false或忽略)
|
|
||||||
rate_limit|速度限制,可忽略
|
|
||||||
flow_limit|流量限制,可忽略
|
|
||||||
remark|客户端备注,可忽略
|
|
||||||
max_conn|最大连接数,可忽略
|
|
||||||
pprof_addr|debug pprof ip:port
|
|
||||||
#### 域名代理
|
|
||||||
|
|
||||||
```ini
|
|
||||||
[common]
|
|
||||||
server_addr=1.1.1.1:8024
|
|
||||||
vkey=123
|
|
||||||
[web1]
|
|
||||||
host=a.proxy.com
|
|
||||||
target_addr=127.0.0.1:8080,127.0.0.1:8082
|
|
||||||
host_change=www.proxy.com
|
|
||||||
header_set_proxy=nps
|
|
||||||
```
|
|
||||||
项 | 含义
|
|
||||||
---|---
|
|
||||||
web1 | 备注
|
|
||||||
host | 域名(http|https都可解析)
|
|
||||||
target_addr|内网目标,负载均衡时多个目标,逗号隔开
|
|
||||||
host_change|请求host修改
|
|
||||||
header_xxx|请求header修改或添加,header_proxy表示添加header proxy:nps
|
|
||||||
|
|
||||||
#### tcp隧道模式
|
|
||||||
|
|
||||||
```ini
|
|
||||||
[common]
|
|
||||||
server_addr=1.1.1.1:8024
|
|
||||||
vkey=123
|
|
||||||
[tcp]
|
|
||||||
mode=tcp
|
|
||||||
target_addr=127.0.0.1:8080
|
|
||||||
server_port=9001
|
|
||||||
```
|
|
||||||
项 | 含义
|
|
||||||
---|---
|
|
||||||
mode | tcp
|
|
||||||
server_port | 在服务端的代理端口
|
|
||||||
tartget_addr|内网目标
|
|
||||||
|
|
||||||
#### udp隧道模式
|
|
||||||
|
|
||||||
```ini
|
|
||||||
[common]
|
|
||||||
server_addr=1.1.1.1:8024
|
|
||||||
vkey=123
|
|
||||||
[udp]
|
|
||||||
mode=udp
|
|
||||||
target_addr=127.0.0.1:8080
|
|
||||||
server_port=9002
|
|
||||||
```
|
|
||||||
项 | 含义
|
|
||||||
---|---
|
|
||||||
mode | udp
|
|
||||||
server_port | 在服务端的代理端口
|
|
||||||
target_addr|内网目标
|
|
||||||
#### http代理模式
|
|
||||||
|
|
||||||
```ini
|
|
||||||
[common]
|
|
||||||
server_addr=1.1.1.1:8024
|
|
||||||
vkey=123
|
|
||||||
[http]
|
|
||||||
mode=httpProxy
|
|
||||||
server_port=9003
|
|
||||||
```
|
|
||||||
项 | 含义
|
|
||||||
---|---
|
|
||||||
mode | httpProxy
|
|
||||||
server_port | 在服务端的代理端口
|
|
||||||
#### socks5代理模式
|
|
||||||
|
|
||||||
```ini
|
|
||||||
[common]
|
|
||||||
server_addr=1.1.1.1:8024
|
|
||||||
vkey=123
|
|
||||||
[socks5]
|
|
||||||
mode=socks5
|
|
||||||
server_port=9004
|
|
||||||
multi_account=multi_account.conf
|
|
||||||
```
|
|
||||||
项 | 含义
|
|
||||||
---|---
|
|
||||||
mode | socks5
|
|
||||||
server_port | 在服务端的代理端口
|
|
||||||
multi_account | socks5多账号配置文件(可选),配置后使用basic_username和basic_password无法通过认证
|
|
||||||
#### 私密代理模式
|
|
||||||
|
|
||||||
```ini
|
|
||||||
[common]
|
|
||||||
server_addr=1.1.1.1:8024
|
|
||||||
vkey=123
|
|
||||||
[secret_ssh]
|
|
||||||
mode=secret
|
|
||||||
password=ssh2
|
|
||||||
target_addr=10.1.50.2:22
|
|
||||||
```
|
|
||||||
项 | 含义
|
|
||||||
---|---
|
|
||||||
mode | secret
|
|
||||||
password | 唯一密钥
|
|
||||||
target_addr|内网目标
|
|
||||||
|
|
||||||
#### p2p代理模式
|
|
||||||
|
|
||||||
```ini
|
|
||||||
[common]
|
|
||||||
server_addr=1.1.1.1:8024
|
|
||||||
vkey=123
|
|
||||||
[p2p_ssh]
|
|
||||||
mode=p2p
|
|
||||||
password=ssh2
|
|
||||||
target_addr=10.1.50.2:22
|
|
||||||
```
|
|
||||||
项 | 含义
|
|
||||||
---|---
|
|
||||||
mode | p2p
|
|
||||||
password | 唯一密钥
|
|
||||||
target_addr|内网目标
|
|
||||||
|
|
||||||
|
|
||||||
#### 文件访问模式
|
|
||||||
利用nps提供一个公网可访问的本地文件服务,此模式仅客户端使用配置文件模式方可启动
|
|
||||||
|
|
||||||
```ini
|
|
||||||
[common]
|
|
||||||
server_addr=1.1.1.1:8024
|
|
||||||
vkey=123
|
|
||||||
[file]
|
|
||||||
mode=file
|
|
||||||
server_port=9100
|
|
||||||
local_path=/tmp/
|
|
||||||
strip_pre=/web/
|
|
||||||
````
|
|
||||||
|
|
||||||
项 | 含义
|
|
||||||
---|---
|
|
||||||
mode | file
|
|
||||||
server_port | 服务端开启的端口
|
|
||||||
local_path|本地文件目录
|
|
||||||
strip_pre|前缀
|
|
||||||
|
|
||||||
对于`strip_pre`,访问公网`ip:9100/web/`相当于访问`/tmp/`目录
|
|
||||||
|
|
||||||
#### 断线重连
|
|
||||||
```ini
|
|
||||||
[common]
|
|
||||||
auto_reconnection=true
|
|
||||||
```
|
|
233
docs/webapi.md
233
docs/webapi.md
@ -1,233 +0,0 @@
|
|||||||
获取客户端列表
|
|
||||||
|
|
||||||
```
|
|
||||||
POST /client/list/
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
| 参数 | 含义 |
|
|
||||||
| --- | --- |
|
|
||||||
| search | 搜索 |
|
|
||||||
| order | 排序asc 正序 desc倒序 |
|
|
||||||
| offset | 分页(第几页) |
|
|
||||||
| limit | 条数(分页显示的条数) |
|
|
||||||
|
|
||||||
***
|
|
||||||
获取单个客户端
|
|
||||||
|
|
||||||
```
|
|
||||||
POST /client/getclient/
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
| 参数 | 含义 |
|
|
||||||
| --- | --- |
|
|
||||||
| id | 客户端id |
|
|
||||||
|
|
||||||
***
|
|
||||||
添加客户端
|
|
||||||
|
|
||||||
```
|
|
||||||
POST /client/add/
|
|
||||||
```
|
|
||||||
|
|
||||||
| 参数 | 含义 |
|
|
||||||
| --- | --- |
|
|
||||||
| remark | 备注 |
|
|
||||||
| u | basic权限认证用户名 |
|
|
||||||
| p | basic权限认证密码 |
|
|
||||||
| limit | 条数(分页显示的条数) |
|
|
||||||
| vkey | 客户端验证密钥 |
|
|
||||||
| config\_conn\_allow | 是否允许客户端以配置文件模式连接 1允许 0不允许 |
|
|
||||||
| compress | 压缩1允许 0不允许 |
|
|
||||||
| crypt | 是否加密(1或者0)1允许 0不允许 |
|
|
||||||
| rate\_limit | 带宽限制 单位KB/S 空则为不限制 |
|
|
||||||
| flow\_limit | 流量限制 单位M 空则为不限制 |
|
|
||||||
| max\_conn | 客户端最大连接数量 空则为不限制 |
|
|
||||||
| max\_tunnel | 客户端最大隧道数量 空则为不限制 |
|
|
||||||
|
|
||||||
***
|
|
||||||
修改客户端
|
|
||||||
|
|
||||||
```
|
|
||||||
POST /client/edit/
|
|
||||||
```
|
|
||||||
|
|
||||||
| 参数 | 含义 |
|
|
||||||
| --- | --- |
|
|
||||||
| remark | 备注 |
|
|
||||||
| u | basic权限认证用户名 |
|
|
||||||
| p | basic权限认证密码 |
|
|
||||||
| limit | 条数(分页显示的条数) |
|
|
||||||
| vkey | 客户端验证密钥 |
|
|
||||||
| config\_conn\_allow | 是否允许客户端以配置文件模式连接 1允许 0不允许 |
|
|
||||||
| compress | 压缩1允许 0不允许 |
|
|
||||||
| crypt | 是否加密(1或者0)1允许 0不允许 |
|
|
||||||
| rate\_limit | 带宽限制 单位KB/S 空则为不限制 |
|
|
||||||
| flow\_limit | 流量限制 单位M 空则为不限制 |
|
|
||||||
| max\_conn | 客户端最大连接数量 空则为不限制 |
|
|
||||||
| max\_tunnel | 客户端最大隧道数量 空则为不限制 |
|
|
||||||
| id | 要修改的客户端id |
|
|
||||||
|
|
||||||
***
|
|
||||||
删除客户端
|
|
||||||
|
|
||||||
```
|
|
||||||
POST /client/del/
|
|
||||||
```
|
|
||||||
|
|
||||||
| 参数 | 含义 |
|
|
||||||
| --- | --- |
|
|
||||||
| id | 要删除的客户端id |
|
|
||||||
|
|
||||||
***
|
|
||||||
获取域名解析列表
|
|
||||||
|
|
||||||
```
|
|
||||||
POST /index/hostlist/
|
|
||||||
```
|
|
||||||
|
|
||||||
| 参数 | 含义 |
|
|
||||||
| --- | --- |
|
|
||||||
| search | 搜索(可以搜域名/备注什么的) |
|
|
||||||
| offset | 分页(第几页) |
|
|
||||||
| limit | 条数(分页显示的条数) |
|
|
||||||
|
|
||||||
***
|
|
||||||
添加域名解析
|
|
||||||
|
|
||||||
```
|
|
||||||
POST /index/addhost/
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
| 参数 | 含义 |
|
|
||||||
| --- | --- |
|
|
||||||
| remark | 备注 |
|
|
||||||
| host | 域名 |
|
|
||||||
| scheme | 协议类型(三种 all http https) |
|
|
||||||
| location | url路由 空则为不限制 |
|
|
||||||
| client\_id | 客户端id |
|
|
||||||
| target | 内网目标(ip:端口) |
|
|
||||||
| header | request header 请求头 |
|
|
||||||
| hostchange | request host 请求主机 |
|
|
||||||
|
|
||||||
***
|
|
||||||
修改域名解析
|
|
||||||
|
|
||||||
```
|
|
||||||
POST /index/edithost/
|
|
||||||
```
|
|
||||||
|
|
||||||
| 参数 | 含义 |
|
|
||||||
| --- | --- |
|
|
||||||
| remark | 备注 |
|
|
||||||
| host | 域名 |
|
|
||||||
| scheme | 协议类型(三种 all http https) |
|
|
||||||
| location | url路由 空则为不限制 |
|
|
||||||
| client\_id | 客户端id |
|
|
||||||
| target | 内网目标(ip:端口) |
|
|
||||||
| header | request header 请求头 |
|
|
||||||
| hostchange | request host 请求主机 |
|
|
||||||
| id | 需要修改的域名解析id |
|
|
||||||
|
|
||||||
***
|
|
||||||
删除域名解析
|
|
||||||
|
|
||||||
```
|
|
||||||
POST /index/delhost/
|
|
||||||
```
|
|
||||||
|
|
||||||
| 参数 | 含义 |
|
|
||||||
| --- | --- |
|
|
||||||
| id | 需要删除的域名解析id |
|
|
||||||
|
|
||||||
***
|
|
||||||
获取单条隧道信息
|
|
||||||
|
|
||||||
```
|
|
||||||
POST /index/getonetunnel/
|
|
||||||
```
|
|
||||||
|
|
||||||
| 参数 | 含义 |
|
|
||||||
| --- | --- |
|
|
||||||
| id | 隧道的id |
|
|
||||||
|
|
||||||
***
|
|
||||||
获取隧道列表
|
|
||||||
|
|
||||||
```
|
|
||||||
POST /index/gettunnel/
|
|
||||||
```
|
|
||||||
|
|
||||||
| 参数 | 含义 |
|
|
||||||
| --- | --- |
|
|
||||||
| client\_id | 穿透隧道的客户端id |
|
|
||||||
| type | 类型tcp udp httpProx socks5 secret p2p |
|
|
||||||
| search | 搜索 |
|
|
||||||
| offset | 分页(第几页) |
|
|
||||||
| limit | 条数(分页显示的条数) |
|
|
||||||
|
|
||||||
***
|
|
||||||
添加隧道
|
|
||||||
|
|
||||||
```
|
|
||||||
POST /index/add/
|
|
||||||
```
|
|
||||||
|
|
||||||
| 参数 | 含义 |
|
|
||||||
| --- | --- |
|
|
||||||
| type | 类型tcp udp httpProx socks5 secret p2p |
|
|
||||||
| remark | 备注 |
|
|
||||||
| port | 服务端端口 |
|
|
||||||
| target | 目标(ip:端口) |
|
|
||||||
| client\_id | 客户端id |
|
|
||||||
|
|
||||||
***
|
|
||||||
修改隧道
|
|
||||||
|
|
||||||
```
|
|
||||||
POST /index/edit/
|
|
||||||
```
|
|
||||||
|
|
||||||
| 参数 | 含义 |
|
|
||||||
| --- | --- |
|
|
||||||
| type | 类型tcp udp httpProx socks5 secret p2p |
|
|
||||||
| remark | 备注 |
|
|
||||||
| port | 服务端端口 |
|
|
||||||
| target | 目标(ip:端口) |
|
|
||||||
| client\_id | 客户端id |
|
|
||||||
| id | 隧道id |
|
|
||||||
|
|
||||||
***
|
|
||||||
删除隧道
|
|
||||||
|
|
||||||
```
|
|
||||||
POST /index/del/
|
|
||||||
```
|
|
||||||
|
|
||||||
| 参数 | 含义 |
|
|
||||||
| --- | --- |
|
|
||||||
| id | 隧道id |
|
|
||||||
|
|
||||||
***
|
|
||||||
隧道停止工作
|
|
||||||
|
|
||||||
```
|
|
||||||
POST /index/stop/
|
|
||||||
```
|
|
||||||
|
|
||||||
| 参数 | 含义 |
|
|
||||||
| --- | --- |
|
|
||||||
| id | 隧道id |
|
|
||||||
|
|
||||||
***
|
|
||||||
隧道开始工作
|
|
||||||
|
|
||||||
```
|
|
||||||
POST /index/start/
|
|
||||||
```
|
|
||||||
|
|
||||||
| 参数 | 含义 |
|
|
||||||
| --- | --- |
|
|
||||||
| id | 隧道id |
|
|
Binary file not shown.
Before Width: | Height: | Size: 26 KiB |
41
go.mod
41
go.mod
@ -1,34 +1,29 @@
|
|||||||
module ehang.io/nps
|
module github.com/cnlh/nps
|
||||||
|
|
||||||
go 1.15
|
go 1.12
|
||||||
|
|
||||||
require (
|
require (
|
||||||
ehang.io/nps-mux v0.0.0-20210407130203-4afa0c10c992
|
github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d // indirect
|
||||||
fyne.io/fyne/v2 v2.0.2
|
|
||||||
github.com/astaxie/beego v1.12.0
|
github.com/astaxie/beego v1.12.0
|
||||||
github.com/bradfitz/iter v0.0.0-20191230175014-e8f45d346db8 // indirect
|
github.com/belogik/goes v0.0.0-20151229125003-e54d722c3aff // indirect
|
||||||
github.com/c4milo/unpackit v0.0.0-20170704181138-4ed373e9ef1c
|
|
||||||
github.com/ccding/go-stun v0.0.0-20180726100737-be486d185f3d
|
github.com/ccding/go-stun v0.0.0-20180726100737-be486d185f3d
|
||||||
github.com/dsnet/compress v0.0.1 // indirect
|
github.com/go-ole/go-ole v1.2.4 // indirect
|
||||||
github.com/golang/snappy v0.0.3
|
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db
|
||||||
github.com/hooklift/assert v0.0.0-20170704181755-9d1defd6d214 // indirect
|
github.com/klauspost/cpuid v1.2.1 // indirect
|
||||||
github.com/kardianos/service v1.2.0
|
github.com/klauspost/reedsolomon v1.9.2 // indirect
|
||||||
github.com/klauspost/cpuid v1.3.1 // indirect
|
github.com/onsi/gomega v1.5.0 // indirect
|
||||||
github.com/klauspost/cpuid/v2 v2.0.6 // indirect
|
github.com/panjf2000/ants/v2 v2.2.2
|
||||||
github.com/klauspost/pgzip v1.2.1 // indirect
|
github.com/pkg/errors v0.8.0
|
||||||
github.com/klauspost/reedsolomon v1.9.12 // indirect
|
|
||||||
github.com/panjf2000/ants/v2 v2.4.2
|
|
||||||
github.com/pkg/errors v0.9.1
|
|
||||||
github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644 // indirect
|
github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644 // indirect
|
||||||
github.com/shirou/gopsutil/v3 v3.21.3
|
github.com/shirou/gopsutil v2.18.12+incompatible
|
||||||
|
github.com/stretchr/testify v1.3.0 // indirect
|
||||||
github.com/templexxx/cpufeat v0.0.0-20180724012125-cef66df7f161 // indirect
|
github.com/templexxx/cpufeat v0.0.0-20180724012125-cef66df7f161 // indirect
|
||||||
github.com/templexxx/xor v0.0.0-20191217153810-f85b25db303b // indirect
|
github.com/templexxx/xor v0.0.0-20181023030647-4e92f724b73b // indirect
|
||||||
github.com/tjfoc/gmsm v1.4.0 // indirect
|
github.com/tjfoc/gmsm v1.0.1 // indirect
|
||||||
github.com/xtaci/kcp-go v5.4.20+incompatible
|
github.com/xtaci/kcp-go v5.4.4+incompatible
|
||||||
github.com/xtaci/lossyconn v0.0.0-20190602105132-8df528c0c9ae // indirect
|
github.com/xtaci/lossyconn v0.0.0-20190602105132-8df528c0c9ae // indirect
|
||||||
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2 // indirect
|
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a
|
||||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4
|
golang.org/x/sys v0.0.0-20190804053845-51ab0e2deafa // indirect
|
||||||
golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57 // indirect
|
|
||||||
)
|
)
|
||||||
|
|
||||||
replace github.com/astaxie/beego => github.com/exfly/beego v1.12.0-export-init
|
replace github.com/astaxie/beego => github.com/exfly/beego v1.12.0-export-init
|
||||||
|
233
go.sum
233
go.sum
@ -1,263 +1,92 @@
|
|||||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
|
||||||
ehang.io/nps-mux v0.0.0-20210407130203-4afa0c10c992 h1:LvlcB+8JveSBprHnva0g+OyLwAH8CRxEwtWzTe6ocoE=
|
|
||||||
ehang.io/nps-mux v0.0.0-20210407130203-4afa0c10c992/go.mod h1:v54y/8ICChiM/aVUuKxGIcWwjm4HGNRyyAwbgLBoMbI=
|
|
||||||
fyne.io/fyne/v2 v2.0.2 h1:6pDvFuCmL1odyT/fPI+2L54hMJW1Zt9Dno41HmLInRs=
|
|
||||||
fyne.io/fyne/v2 v2.0.2/go.mod h1:3+FYmLJVgeb8EvTPJ5YzZeo7LkAq4bbuY3Zrir6xHbg=
|
|
||||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
|
||||||
github.com/Knetic/govaluate v3.0.0+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
|
github.com/Knetic/govaluate v3.0.0+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
|
||||||
github.com/Kodeworks/golang-image-ico v0.0.0-20141118225523-73f0f4cfade9/go.mod h1:7uhhqiBaR4CpN0k9rMjOtjpcfGd6DG2m04zQxKnWQ0I=
|
|
||||||
github.com/OwnLocal/goes v1.0.0/go.mod h1:8rIFjBGTue3lCU0wplczcUgt9Gxgrkkrw7etMIcn8TM=
|
github.com/OwnLocal/goes v1.0.0/go.mod h1:8rIFjBGTue3lCU0wplczcUgt9Gxgrkkrw7etMIcn8TM=
|
||||||
github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d h1:G0m3OIz70MZUWq3EgK3CesDbo8upS2Vm9/P3FtgI+Jk=
|
github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d h1:G0m3OIz70MZUWq3EgK3CesDbo8upS2Vm9/P3FtgI+Jk=
|
||||||
github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg=
|
github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg=
|
||||||
github.com/akavel/rsrc v0.8.0/go.mod h1:uLoCtb9J+EyAqh+26kdrTgmzRBFPGOolLWKpdxkKq+c=
|
github.com/astaxie/beego v1.12.0 h1:MRhVoeeye5N+Flul5PoVfD9CslfdoH+xqC/xvSQ5u2Y=
|
||||||
|
github.com/astaxie/beego v1.12.0/go.mod h1:fysx+LZNZKnvh4GED/xND7jWtjCR6HzydR2Hh2Im57o=
|
||||||
github.com/beego/goyaml2 v0.0.0-20130207012346-5545475820dd/go.mod h1:1b+Y/CofkYwXMUU0OhQqGvsY2Bvgr4j6jfT699wyZKQ=
|
github.com/beego/goyaml2 v0.0.0-20130207012346-5545475820dd/go.mod h1:1b+Y/CofkYwXMUU0OhQqGvsY2Bvgr4j6jfT699wyZKQ=
|
||||||
github.com/beego/x2j v0.0.0-20131220205130-a0352aadc542/go.mod h1:kSeGC/p1AbBiEp5kat81+DSQrZenVBZXklMLaELspWU=
|
github.com/beego/x2j v0.0.0-20131220205130-a0352aadc542/go.mod h1:kSeGC/p1AbBiEp5kat81+DSQrZenVBZXklMLaELspWU=
|
||||||
|
github.com/belogik/goes v0.0.0-20151229125003-e54d722c3aff/go.mod h1:PhH1ZhyCzHKt4uAasyx+ljRCgoezetRNf59CUtwUkqY=
|
||||||
github.com/bradfitz/gomemcache v0.0.0-20180710155616-bc664df96737/go.mod h1:PmM6Mmwb0LSuEubjR8N7PtNe1KxZLtOUHtbeikc5h60=
|
github.com/bradfitz/gomemcache v0.0.0-20180710155616-bc664df96737/go.mod h1:PmM6Mmwb0LSuEubjR8N7PtNe1KxZLtOUHtbeikc5h60=
|
||||||
github.com/bradfitz/iter v0.0.0-20191230175014-e8f45d346db8 h1:GKTyiRCL6zVf5wWaqKnf+7Qs6GbEPfd4iMOitWzXJx8=
|
|
||||||
github.com/bradfitz/iter v0.0.0-20191230175014-e8f45d346db8/go.mod h1:spo1JLcs67NmW1aVLEgtA8Yy1elc+X8y5SRW1sFW4Og=
|
|
||||||
github.com/c4milo/unpackit v0.0.0-20170704181138-4ed373e9ef1c h1:aprLqMn7gSPT+vdDSl+/E6NLEuArwD/J7IWd8bJt5lQ=
|
|
||||||
github.com/c4milo/unpackit v0.0.0-20170704181138-4ed373e9ef1c/go.mod h1:Ie6SubJv/NTO9Q0UBH0QCl3Ve50lu9hjbi5YJUw03TE=
|
|
||||||
github.com/casbin/casbin v1.7.0/go.mod h1:c67qKN6Oum3UF5Q1+BByfFxkwKvhwW57ITjqwtzR1KE=
|
github.com/casbin/casbin v1.7.0/go.mod h1:c67qKN6Oum3UF5Q1+BByfFxkwKvhwW57ITjqwtzR1KE=
|
||||||
github.com/ccding/go-stun v0.0.0-20180726100737-be486d185f3d h1:As4937T5NVbJ/DmZT9z33pyLEprMd6CUSfhbmMY57Io=
|
github.com/ccding/go-stun v0.0.0-20180726100737-be486d185f3d h1:As4937T5NVbJ/DmZT9z33pyLEprMd6CUSfhbmMY57Io=
|
||||||
github.com/ccding/go-stun v0.0.0-20180726100737-be486d185f3d/go.mod h1:3FK1bMar37f7jqVY7q/63k3OMX1c47pGCufzt3X0sYE=
|
github.com/ccding/go-stun v0.0.0-20180726100737-be486d185f3d/go.mod h1:3FK1bMar37f7jqVY7q/63k3OMX1c47pGCufzt3X0sYE=
|
||||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
|
||||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
|
||||||
github.com/cloudflare/golz4 v0.0.0-20150217214814-ef862a3cdc58/go.mod h1:EOBUe0h4xcZ5GoxqC5SDxFQ8gwyZPKQoEzownBlhI80=
|
github.com/cloudflare/golz4 v0.0.0-20150217214814-ef862a3cdc58/go.mod h1:EOBUe0h4xcZ5GoxqC5SDxFQ8gwyZPKQoEzownBlhI80=
|
||||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
|
||||||
github.com/couchbase/go-couchbase v0.0.0-20181122212707-3e9b6e1258bb/go.mod h1:TWI8EKQMs5u5jLKW/tsb9VwauIrMIxQG1r5fMsswK5U=
|
github.com/couchbase/go-couchbase v0.0.0-20181122212707-3e9b6e1258bb/go.mod h1:TWI8EKQMs5u5jLKW/tsb9VwauIrMIxQG1r5fMsswK5U=
|
||||||
github.com/couchbase/gomemcached v0.0.0-20181122193126-5125a94a666c/go.mod h1:srVSlQLB8iXBVXHgnqemxUXqN6FCvClgCMPCsjBDR7c=
|
github.com/couchbase/gomemcached v0.0.0-20181122193126-5125a94a666c/go.mod h1:srVSlQLB8iXBVXHgnqemxUXqN6FCvClgCMPCsjBDR7c=
|
||||||
github.com/couchbase/goutils v0.0.0-20180530154633-e865a1461c8a/go.mod h1:BQwMFlJzDjFDG3DJUdU0KORxn88UlsOULuxLExMh3Hs=
|
github.com/couchbase/goutils v0.0.0-20180530154633-e865a1461c8a/go.mod h1:BQwMFlJzDjFDG3DJUdU0KORxn88UlsOULuxLExMh3Hs=
|
||||||
github.com/cupcake/rdb v0.0.0-20161107195141-43ba34106c76/go.mod h1:vYwsqCOLxGiisLwp9rITslkFNpZD5rz43tf41QFkTWY=
|
github.com/cupcake/rdb v0.0.0-20161107195141-43ba34106c76/go.mod h1:vYwsqCOLxGiisLwp9rITslkFNpZD5rz43tf41QFkTWY=
|
||||||
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
|
||||||
github.com/dsnet/compress v0.0.1 h1:PlZu0n3Tuv04TzpfPbrnI0HW/YwodEXDS+oPKahKF0Q=
|
|
||||||
github.com/dsnet/compress v0.0.1/go.mod h1:Aw8dCMJ7RioblQeTqt88akK31OvO8Dhf5JflhBbQEHo=
|
|
||||||
github.com/dsnet/golib v0.0.0-20171103203638-1ea166775780/go.mod h1:Lj+Z9rebOhdfkVLjJ8T6VcRQv3SXugXy999NBtR9aFY=
|
|
||||||
github.com/edsrzf/mmap-go v0.0.0-20170320065105-0bce6a688712/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
|
github.com/edsrzf/mmap-go v0.0.0-20170320065105-0bce6a688712/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
|
||||||
github.com/elazarl/go-bindata-assetfs v1.0.0 h1:G/bYguwHIzWq9ZoyUQqrjTmJbbYn3j3CKKpKinvZLFk=
|
github.com/elazarl/go-bindata-assetfs v1.0.0 h1:G/bYguwHIzWq9ZoyUQqrjTmJbbYn3j3CKKpKinvZLFk=
|
||||||
github.com/elazarl/go-bindata-assetfs v1.0.0/go.mod h1:v+YaWX3bdea5J/mo8dSETolEo7R71Vk1u8bnjau5yw4=
|
github.com/elazarl/go-bindata-assetfs v1.0.0/go.mod h1:v+YaWX3bdea5J/mo8dSETolEo7R71Vk1u8bnjau5yw4=
|
||||||
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
|
||||||
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
|
||||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
|
||||||
github.com/exfly/beego v1.12.0-export-init h1:VQNYKdXhAwZGUaFmQv8Aj921O3rQJZRIF8xeGrhsjrI=
|
github.com/exfly/beego v1.12.0-export-init h1:VQNYKdXhAwZGUaFmQv8Aj921O3rQJZRIF8xeGrhsjrI=
|
||||||
github.com/exfly/beego v1.12.0-export-init/go.mod h1:fysx+LZNZKnvh4GED/xND7jWtjCR6HzydR2Hh2Im57o=
|
github.com/exfly/beego v1.12.0-export-init/go.mod h1:fysx+LZNZKnvh4GED/xND7jWtjCR6HzydR2Hh2Im57o=
|
||||||
github.com/fredbi/uri v0.0.0-20181227131451-3dcfdacbaaf3 h1:FDqhDm7pcsLhhWl1QtD8vlzI4mm59llRvNzrFg6/LAA=
|
github.com/exfly/beego v1.12.0 h1:OXwIwngaAx35Mga+jLiZmArusBxj8/H0jYXzGDAdwOg=
|
||||||
github.com/fredbi/uri v0.0.0-20181227131451-3dcfdacbaaf3/go.mod h1:CzM2G82Q9BDUvMTGHnXf/6OExw/Dz2ivDj48nVg7Lg8=
|
github.com/exfly/beego v1.12.0/go.mod h1:fysx+LZNZKnvh4GED/xND7jWtjCR6HzydR2Hh2Im57o=
|
||||||
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
|
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
|
||||||
github.com/fyne-io/mobile v0.1.3-0.20210318200029-09e9c4e13a8f h1:rguJ/t99j/6zRSFzsBKlsmmyl+vOvCeTJ+2uTBvuXFI=
|
|
||||||
github.com/fyne-io/mobile v0.1.3-0.20210318200029-09e9c4e13a8f/go.mod h1:/kOrWrZB6sasLbEy2JIvr4arEzQTXBTZGb3Y96yWbHY=
|
|
||||||
github.com/go-gl/gl v0.0.0-20190320180904-bf2b1f2f34d7 h1:SCYMcCJ89LjRGwEa0tRluNRiMjZHalQZrVrvTbPh+qw=
|
|
||||||
github.com/go-gl/gl v0.0.0-20190320180904-bf2b1f2f34d7/go.mod h1:482civXOzJJCPzJ4ZOX/pwvXBWSnzD4OKMdH4ClKGbk=
|
|
||||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20210311203641-62640a716d48 h1:QrUfZrT8n72FUuiABt4tbu8PwDnOPAbnj3Mql1UhdRI=
|
|
||||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20210311203641-62640a716d48/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
|
||||||
github.com/go-ole/go-ole v1.2.4 h1:nNBDSCOigTSiarFpYE9J/KtEA1IOW4CNeqT9TQDqCxI=
|
github.com/go-ole/go-ole v1.2.4 h1:nNBDSCOigTSiarFpYE9J/KtEA1IOW4CNeqT9TQDqCxI=
|
||||||
github.com/go-ole/go-ole v1.2.4/go.mod h1:XCwSNxSkXRo4vlyPy93sltvi/qJq0jqQhjqQNIwKuxM=
|
github.com/go-ole/go-ole v1.2.4/go.mod h1:XCwSNxSkXRo4vlyPy93sltvi/qJq0jqQhjqQNIwKuxM=
|
||||||
github.com/go-redis/redis v6.14.2+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA=
|
github.com/go-redis/redis v6.14.2+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA=
|
||||||
github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
|
github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
|
||||||
github.com/godbus/dbus/v5 v5.0.3 h1:ZqHaoEF7TBzh4jzPmqVhE/5A1z9of6orkAe5uHoAeME=
|
|
||||||
github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
|
||||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||||
github.com/goki/freetype v0.0.0-20181231101311-fa8a33aabaff h1:W71vTCKoxtdXgnm1ECDFkfQnpdqAO00zzGXLA5yaEX8=
|
|
||||||
github.com/goki/freetype v0.0.0-20181231101311-fa8a33aabaff/go.mod h1:wfqRWLHRBsRgkp5dmbG56SA0DmVtwrF5N3oPdI8t+Aw=
|
|
||||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
|
||||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
|
||||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
|
||||||
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
|
||||||
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
|
||||||
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
|
|
||||||
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
|
|
||||||
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
|
|
||||||
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
|
||||||
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
|
||||||
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db h1:woRePGFeVFfLKN/pOkfl+p/TAqKOfFu+7KPlMVpok/w=
|
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db h1:woRePGFeVFfLKN/pOkfl+p/TAqKOfFu+7KPlMVpok/w=
|
||||||
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||||
github.com/golang/snappy v0.0.3 h1:fHPg5GQYlCeLIPB9BZqMVR5nR9A+IM5zcgeTdjMYmLA=
|
|
||||||
github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
|
||||||
github.com/gomodule/redigo v2.0.0+incompatible/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4=
|
github.com/gomodule/redigo v2.0.0+incompatible/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4=
|
||||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
github.com/klauspost/cpuid v1.2.1 h1:vJi+O/nMdFt0vqm8NZBI6wzALWdA2X+egi0ogNyrC/w=
|
||||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
|
||||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
github.com/klauspost/reedsolomon v1.9.2 h1:E9CMS2Pqbv+C7tsrYad4YC9MfhnMVWhMRsTi7U0UB18=
|
||||||
github.com/hooklift/assert v0.0.0-20170704181755-9d1defd6d214 h1:WgfvpuKg42WVLkxNwzfFraXkTXPK36bMqXvMFN67clI=
|
github.com/klauspost/reedsolomon v1.9.2/go.mod h1:CwCi+NUr9pqSVktrkN+Ondf06rkhYZ/pcNv7fu+8Un4=
|
||||||
github.com/hooklift/assert v0.0.0-20170704181755-9d1defd6d214/go.mod h1:kj6hFWqfwSjFjLnYW5PK1DoxZ4O0uapwHRmd9jhln4E=
|
|
||||||
github.com/jackmordaunt/icns v0.0.0-20181231085925-4f16af745526/go.mod h1:UQkeMHVoNcyXYq9otUupF7/h/2tmHlhrS2zw7ZVvUqc=
|
|
||||||
github.com/josephspurrier/goversioninfo v0.0.0-20200309025242-14b0ab84c6ca/go.mod h1:eJTEwMjXb7kZ633hO3Ln9mBUCOjX2+FlTljvpl9SYdE=
|
|
||||||
github.com/kardianos/service v1.2.0 h1:bGuZ/epo3vrt8IPC7mnKQolqFeYJb7Cs8Rk4PSOBB/g=
|
|
||||||
github.com/kardianos/service v1.2.0/go.mod h1:CIMRFEJVL+0DS1a3Nx06NaMn4Dz63Ng6O7dl0qH0zVM=
|
|
||||||
github.com/klauspost/compress v1.4.1 h1:8VMb5+0wMgdBykOV96DwNwKFQ+WTI4pzYURP99CcB9E=
|
|
||||||
github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
|
|
||||||
github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
|
|
||||||
github.com/klauspost/cpuid v1.3.1 h1:5JNjFYYQrZeKRJ0734q51WCEEn2huer72Dc7K+R/b6s=
|
|
||||||
github.com/klauspost/cpuid v1.3.1/go.mod h1:bYW4mA6ZgKPob1/Dlai2LviZJO7KGI3uoWLd42rAQw4=
|
|
||||||
github.com/klauspost/cpuid/v2 v2.0.2 h1:pd2FBxFydtPn2ywTLStbFg9CJKrojATnpeJWSP7Ys4k=
|
|
||||||
github.com/klauspost/cpuid/v2 v2.0.2/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
|
||||||
github.com/klauspost/cpuid/v2 v2.0.6 h1:dQ5ueTiftKxp0gyjKSx5+8BtPWkyQbd95m8Gys/RarI=
|
|
||||||
github.com/klauspost/cpuid/v2 v2.0.6/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
|
||||||
github.com/klauspost/pgzip v1.2.1 h1:oIPZROsWuPHpOdMVWLuJZXwgjhrW8r1yEX8UqMyeNHM=
|
|
||||||
github.com/klauspost/pgzip v1.2.1/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
|
|
||||||
github.com/klauspost/reedsolomon v1.9.12 h1:EyOucRmcrLH+2hqKGdoA5SM8pwPKR6BJsf3r6zpYOA0=
|
|
||||||
github.com/klauspost/reedsolomon v1.9.12/go.mod h1:nLvuzNvy1ZDNQW30IuMc2ZWCbiqrJgdLoUS2X8HAUVg=
|
|
||||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
|
||||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
|
||||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
|
||||||
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||||
github.com/lucor/goinfo v0.0.0-20200401173949-526b5363a13a/go.mod h1:ORP3/rB5IsulLEBwQZCJyyV6niqmI7P4EWSmkug+1Ng=
|
|
||||||
github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
||||||
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ=
|
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||||
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8=
|
github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
|
github.com/panjf2000/ants/v2 v2.2.2 h1:TWzusBjq/IflXhy+/S6u5wmMLCBdJnB9tPIx9Zmhvok=
|
||||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
github.com/panjf2000/ants/v2 v2.2.2/go.mod h1:1GFm8bV8nyCQvU5K4WvBCTG1/YBFOD2VzjffD8fV55A=
|
||||||
github.com/panjf2000/ants/v2 v2.4.2 h1:kesjjo8JipN3vNNg1XaiXaeSs6xJweBTgenkBtsrHf8=
|
|
||||||
github.com/panjf2000/ants/v2 v2.4.2/go.mod h1:f6F0NZVFsGCp5A7QW/Zj/m92atWwOkY0OIhFxRNFr4A=
|
|
||||||
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
||||||
github.com/pkg/errors v0.8.0 h1:WdK/asTD0HN+q6hsWO3/vpuAkAr+tw6aNJNDFFf0+qw=
|
github.com/pkg/errors v0.8.0 h1:WdK/asTD0HN+q6hsWO3/vpuAkAr+tw6aNJNDFFf0+qw=
|
||||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
|
||||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
|
||||||
github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644 h1:X+yvsM2yrEktyI+b2qND5gpH8YhURn0k8OCaeRnkINo=
|
github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644 h1:X+yvsM2yrEktyI+b2qND5gpH8YhURn0k8OCaeRnkINo=
|
||||||
github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644/go.mod h1:nkxAfR/5quYxwPZhyDxgasBMnRtBZd0FCEpawpjMUFg=
|
github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644/go.mod h1:nkxAfR/5quYxwPZhyDxgasBMnRtBZd0FCEpawpjMUFg=
|
||||||
github.com/shirou/gopsutil/v3 v3.21.3 h1:wgcdAHZS2H6qy4JFewVTtqfiYxFzCeEJod/mLztdPG8=
|
github.com/shirou/gopsutil v2.18.12+incompatible h1:1eaJvGomDnH74/5cF4CTmTbLHAriGFsTZppLXDX93OM=
|
||||||
github.com/shirou/gopsutil/v3 v3.21.3/go.mod h1:ghfMypLDrFSWN2c9cDYFLHyynQ+QUht0cv/18ZqVczw=
|
github.com/shirou/gopsutil v2.18.12+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
|
||||||
github.com/siddontang/go v0.0.0-20180604090527-bdc77568d726/go.mod h1:3yhqj7WBBfRhbBlzyOC3gUxftwsU0u8gqevxwIHQpMw=
|
github.com/siddontang/go v0.0.0-20180604090527-bdc77568d726/go.mod h1:3yhqj7WBBfRhbBlzyOC3gUxftwsU0u8gqevxwIHQpMw=
|
||||||
github.com/siddontang/ledisdb v0.0.0-20181029004158-becf5f38d373/go.mod h1:mF1DpOSOUiJRMR+FDqaqu3EBqrybQtrDDszLUZ6oxPg=
|
github.com/siddontang/ledisdb v0.0.0-20181029004158-becf5f38d373/go.mod h1:mF1DpOSOUiJRMR+FDqaqu3EBqrybQtrDDszLUZ6oxPg=
|
||||||
github.com/siddontang/rdb v0.0.0-20150307021120-fc89ed2e418d/go.mod h1:AMEsy7v5z92TR1JKMkLLoaOQk++LVnOKL3ScbJ8GNGA=
|
github.com/siddontang/rdb v0.0.0-20150307021120-fc89ed2e418d/go.mod h1:AMEsy7v5z92TR1JKMkLLoaOQk++LVnOKL3ScbJ8GNGA=
|
||||||
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
|
|
||||||
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
|
||||||
github.com/srwiley/oksvg v0.0.0-20200311192757-870daf9aa564 h1:HunZiaEKNGVdhTRQOVpMmj5MQnGnv+e8uZNu3xFLgyM=
|
|
||||||
github.com/srwiley/oksvg v0.0.0-20200311192757-870daf9aa564/go.mod h1:afMbS0qvv1m5tfENCwnOdZGOF8RGR/FsZ7bvBxQGZG4=
|
|
||||||
github.com/srwiley/rasterx v0.0.0-20200120212402-85cb7272f5e9 h1:m59mIOBO4kfcNCEzJNy71UkeF4XIx2EVmL9KLwDQdmM=
|
|
||||||
github.com/srwiley/rasterx v0.0.0-20200120212402-85cb7272f5e9/go.mod h1:mvWM0+15UqyrFKqdRjY6LuAVJR0HOVhJlEgZ5JWtSWU=
|
|
||||||
github.com/ssdb/gossdb v0.0.0-20180723034631-88f6b59b84ec/go.mod h1:QBvMkMya+gXctz3kmljlUCu/yB3GZ6oee+dUozsezQE=
|
github.com/ssdb/gossdb v0.0.0-20180723034631-88f6b59b84ec/go.mod h1:QBvMkMya+gXctz3kmljlUCu/yB3GZ6oee+dUozsezQE=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
|
||||||
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
|
||||||
github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4=
|
|
||||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
|
||||||
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
|
|
||||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
|
||||||
github.com/syndtr/goleveldb v0.0.0-20181127023241-353a9fca669c/go.mod h1:Z4AUp2Km+PwemOoO/VB5AOx9XSsIItzFjoJlOSiYmn0=
|
github.com/syndtr/goleveldb v0.0.0-20181127023241-353a9fca669c/go.mod h1:Z4AUp2Km+PwemOoO/VB5AOx9XSsIItzFjoJlOSiYmn0=
|
||||||
github.com/templexxx/cpufeat v0.0.0-20180724012125-cef66df7f161 h1:89CEmDvlq/F7SJEOqkIdNDGJXrQIhuIx9D2DBXjavSU=
|
github.com/templexxx/cpufeat v0.0.0-20180724012125-cef66df7f161 h1:89CEmDvlq/F7SJEOqkIdNDGJXrQIhuIx9D2DBXjavSU=
|
||||||
github.com/templexxx/cpufeat v0.0.0-20180724012125-cef66df7f161/go.mod h1:wM7WEvslTq+iOEAMDLSzhVuOt5BRZ05WirO+b09GHQU=
|
github.com/templexxx/cpufeat v0.0.0-20180724012125-cef66df7f161/go.mod h1:wM7WEvslTq+iOEAMDLSzhVuOt5BRZ05WirO+b09GHQU=
|
||||||
github.com/templexxx/xor v0.0.0-20191217153810-f85b25db303b h1:fj5tQ8acgNUr6O8LEplsxDhUIe2573iLkJc+PqnzZTI=
|
github.com/templexxx/xor v0.0.0-20181023030647-4e92f724b73b h1:mnG1fcsIB1d/3vbkBak2MM0u+vhGhlQwpeimUi7QncM=
|
||||||
github.com/templexxx/xor v0.0.0-20191217153810-f85b25db303b/go.mod h1:5XA7W9S6mni3h5uvOC75dA3m9CCCaS83lltmc0ukdi4=
|
github.com/templexxx/xor v0.0.0-20181023030647-4e92f724b73b/go.mod h1:5XA7W9S6mni3h5uvOC75dA3m9CCCaS83lltmc0ukdi4=
|
||||||
github.com/tjfoc/gmsm v1.4.0 h1:8nbaiZG+iVdh+fXVw0DZoZZa7a4TGm3Qab+xdrdzj8s=
|
github.com/tjfoc/gmsm v1.0.1 h1:R11HlqhXkDospckjZEihx9SW/2VW0RgdwrykyWMFOQU=
|
||||||
github.com/tjfoc/gmsm v1.4.0/go.mod h1:j4INPkHWMrhJb38G+J6W4Tw0AbuN8Thu3PbdVYhVcTE=
|
github.com/tjfoc/gmsm v1.0.1/go.mod h1:XxO4hdhhrzAd+G4CjDqaOkd0hUzmtPR/d3EiBBMn/wc=
|
||||||
github.com/tklauser/go-sysconf v0.3.4 h1:HT8SVixZd3IzLdfs/xlpq0jeSfTX57g1v6wB1EuzV7M=
|
|
||||||
github.com/tklauser/go-sysconf v0.3.4/go.mod h1:Cl2c8ZRWfHD5IrfHo9VN+FX9kCFjIOyVklgXycLB6ek=
|
|
||||||
github.com/tklauser/numcpus v0.2.1 h1:ct88eFm+Q7m2ZfXJdan1xYoXKlmwsfP+k88q05KvlZc=
|
|
||||||
github.com/tklauser/numcpus v0.2.1/go.mod h1:9aU+wOc6WjUIZEwWMP62PL/41d65P+iks1gBkr4QyP8=
|
|
||||||
github.com/ulikunitz/xz v0.5.6 h1:jGHAfXawEGZQ3blwU5wnWKQJvAraT7Ftq9EXjnXYgt8=
|
|
||||||
github.com/ulikunitz/xz v0.5.6/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4ABRW8=
|
|
||||||
github.com/wendal/errors v0.0.0-20130201093226-f66c77a7882b/go.mod h1:Q12BUT7DqIlHRmgv3RskH+UCM/4eqVMgI0EMmlSpAXc=
|
github.com/wendal/errors v0.0.0-20130201093226-f66c77a7882b/go.mod h1:Q12BUT7DqIlHRmgv3RskH+UCM/4eqVMgI0EMmlSpAXc=
|
||||||
github.com/xtaci/kcp-go v5.4.20+incompatible h1:TN1uey3Raw0sTz0Fg8GkfM0uH3YwzhnZWQ1bABv5xAg=
|
github.com/xtaci/kcp-go v5.4.4+incompatible h1:QIJ0a0Q0N1G20yLHL2+fpdzyy2v/Cb3PI+xiwx/KK9c=
|
||||||
github.com/xtaci/kcp-go v5.4.20+incompatible/go.mod h1:bN6vIwHQbfHaHtFpEssmWsN45a+AZwO7eyRCmEIbtvE=
|
github.com/xtaci/kcp-go v5.4.4+incompatible/go.mod h1:bN6vIwHQbfHaHtFpEssmWsN45a+AZwO7eyRCmEIbtvE=
|
||||||
github.com/xtaci/lossyconn v0.0.0-20190602105132-8df528c0c9ae h1:J0GxkO96kL4WF+AIT3M4mfUVinOCPgf2uUWYFUzN0sM=
|
github.com/xtaci/lossyconn v0.0.0-20190602105132-8df528c0c9ae h1:J0GxkO96kL4WF+AIT3M4mfUVinOCPgf2uUWYFUzN0sM=
|
||||||
github.com/xtaci/lossyconn v0.0.0-20190602105132-8df528c0c9ae/go.mod h1:gXtu8J62kEgmN++bm9BVICuT/e8yiLI2KFobd/TRFsE=
|
github.com/xtaci/lossyconn v0.0.0-20190602105132-8df528c0c9ae/go.mod h1:gXtu8J62kEgmN++bm9BVICuT/e8yiLI2KFobd/TRFsE=
|
||||||
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
|
||||||
golang.org/x/crypto v0.0.0-20181127143415-eb0de9b17e85 h1:et7+NAX3lLIk5qUCTA9QelBjGE/NkhzYw/mhnr0s7nI=
|
golang.org/x/crypto v0.0.0-20181127143415-eb0de9b17e85 h1:et7+NAX3lLIk5qUCTA9QelBjGE/NkhzYw/mhnr0s7nI=
|
||||||
golang.org/x/crypto v0.0.0-20181127143415-eb0de9b17e85/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
golang.org/x/crypto v0.0.0-20181127143415-eb0de9b17e85/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
|
||||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
|
||||||
golang.org/x/crypto v0.0.0-20201012173705-84dcc777aaee/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
|
||||||
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2 h1:It14KIkyBFYkHkwZ7k45minvA9aorojkyjGk9KJ5B/w=
|
|
||||||
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
|
||||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
|
||||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b h1:+qEpEAPhDZ1o0x3tHzZTQDArnOixOzGD9HUJfcg0mb4=
|
|
||||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
|
||||||
golang.org/x/image v0.0.0-20200430140353-33d19683fad8 h1:6WW6V3x1P/jokJBpRQYUJnMHRP6isStQwCozxnU7XQw=
|
|
||||||
golang.org/x/image v0.0.0-20200430140353-33d19683fad8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
|
||||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
|
||||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
|
||||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
|
||||||
golang.org/x/mod v0.2.0 h1:KU7oHjnv3XNWfa5COkzUifxZmxp1TyI7ImMXqFxLwvQ=
|
|
||||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
|
||||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
|
||||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
|
||||||
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a h1:gOpx8G595UYyvj8UK4+OFyY4rx037g3fmfhe5SasG3U=
|
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a h1:gOpx8G595UYyvj8UK4+OFyY4rx037g3fmfhe5SasG3U=
|
||||||
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
|
||||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
|
||||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
|
||||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
|
||||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
|
||||||
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
|
||||||
golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
|
||||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
|
||||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 h1:4nGaVu0QrbjT/AK2PRLuQfQuh6DJve+pELhqTdAj3x0=
|
|
||||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
|
||||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
|
||||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sys v0.0.0-20190804053845-51ab0e2deafa h1:KIDDMLT1O0Nr7TSxp8xM5tJcdn8tgyAONntO829og1M=
|
||||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sys v0.0.0-20190804053845-51ab0e2deafa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
|
||||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20200720211630-cb9d2d5c5666/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20201015000850-e3ed0017c211 h1:9UQO31fZ+0aKQOFldThf7BKPMJTiBfWycGh/u3UoO88=
|
|
||||||
golang.org/x/sys v0.0.0-20201015000850-e3ed0017c211/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20210217105451-b926d437f341/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57 h1:F5Gozwx4I1xtr/sr/8CFbb57iKi3297KFs0QDbGN60A=
|
|
||||||
golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
|
||||||
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
|
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
|
|
||||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
|
||||||
golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
|
|
||||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
|
||||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
|
||||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
|
||||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
|
||||||
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
|
||||||
golang.org/x/tools v0.0.0-20190808195139-e713427fea3f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
|
||||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
|
||||||
golang.org/x/tools v0.0.0-20200328031815-3db5fc6bac03/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
|
|
||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
|
||||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
|
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
|
||||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
|
||||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
|
||||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
|
||||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
|
||||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
|
||||||
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
|
||||||
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
|
|
||||||
google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
|
||||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
|
||||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
|
||||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
|
||||||
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
|
|
||||||
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
|
||||||
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
|
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||||
gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE=
|
gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE=
|
||||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
|
||||||
gopkg.in/yaml.v2 v2.2.7 h1:VUgggvou5XRW9mHwD/yXxIYSMtY0zoKQf/v226p2nyo=
|
|
||||||
gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
|
||||||
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
|
|
||||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
|
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
|
||||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
|
||||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
|
||||||
|
@ -1,20 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<manifest
|
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
package="org.nps.client"
|
|
||||||
android:versionCode="1"
|
|
||||||
android:versionName="0.26.10">
|
|
||||||
|
|
||||||
<application android:label="Npc" android:debuggable="true">
|
|
||||||
<activity android:name="org.golang.app.GoNativeActivity"
|
|
||||||
android:label="Npc"
|
|
||||||
android:configChanges="orientation|keyboardHidden">
|
|
||||||
<meta-data android:name="android.app.lib_name" android:value="npc"/>
|
|
||||||
<intent-filter>
|
|
||||||
<action android:name="android.intent.action.MAIN"/>
|
|
||||||
<category android:name="android.intent.category.LAUNCHER"/>
|
|
||||||
</intent-filter>
|
|
||||||
</activity>
|
|
||||||
</application>
|
|
||||||
<uses-permission android:name="android.permission.INTERNET"/>
|
|
||||||
</manifest>
|
|
194
gui/npc/npc.go
194
gui/npc/npc.go
@ -1,194 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"ehang.io/nps/client"
|
|
||||||
"ehang.io/nps/lib/common"
|
|
||||||
"ehang.io/nps/lib/daemon"
|
|
||||||
"ehang.io/nps/lib/version"
|
|
||||||
"fmt"
|
|
||||||
"fyne.io/fyne/v2"
|
|
||||||
"fyne.io/fyne/v2/app"
|
|
||||||
"fyne.io/fyne/v2/container"
|
|
||||||
"fyne.io/fyne/v2/layout"
|
|
||||||
"fyne.io/fyne/v2/widget"
|
|
||||||
"github.com/astaxie/beego/logs"
|
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
|
||||||
"path"
|
|
||||||
"runtime"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
daemon.InitDaemon("npc", common.GetRunPath(), common.GetTmpPath())
|
|
||||||
logs.SetLogger("store")
|
|
||||||
application := app.New()
|
|
||||||
window := application.NewWindow("Npc " + version.VERSION)
|
|
||||||
window.SetContent(WidgetScreen())
|
|
||||||
window.Resize(fyne.NewSize(910, 350))
|
|
||||||
|
|
||||||
window.ShowAndRun()
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
start bool
|
|
||||||
closing bool
|
|
||||||
status = "Start!"
|
|
||||||
connType = "tcp"
|
|
||||||
cl = new(client.TRPClient)
|
|
||||||
refreshCh = make(chan struct{})
|
|
||||||
)
|
|
||||||
|
|
||||||
func WidgetScreen() fyne.CanvasObject {
|
|
||||||
return fyne.NewContainerWithLayout(layout.NewBorderLayout(nil, nil, nil, nil),
|
|
||||||
makeMainTab(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
func makeMainTab() *fyne.Container {
|
|
||||||
serverPort := widget.NewEntry()
|
|
||||||
serverPort.SetPlaceHolder("Server:Port")
|
|
||||||
|
|
||||||
vKey := widget.NewEntry()
|
|
||||||
vKey.SetPlaceHolder("Vkey")
|
|
||||||
radio := widget.NewRadioGroup([]string{"tcp", "kcp"}, func(s string) { connType = s })
|
|
||||||
radio.Horizontal = true
|
|
||||||
|
|
||||||
button := widget.NewButton(status, func() {
|
|
||||||
onclick(serverPort.Text, vKey.Text, connType)
|
|
||||||
})
|
|
||||||
go func() {
|
|
||||||
for {
|
|
||||||
<-refreshCh
|
|
||||||
button.SetText(status)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
lo := widget.NewMultiLineEntry()
|
|
||||||
lo.Disable()
|
|
||||||
lo.Resize(fyne.NewSize(910, 250))
|
|
||||||
slo := container.NewScroll(lo)
|
|
||||||
slo.Resize(fyne.NewSize(910, 250))
|
|
||||||
go func() {
|
|
||||||
for {
|
|
||||||
time.Sleep(time.Second)
|
|
||||||
lo.SetText(common.GetLogMsg())
|
|
||||||
slo.Resize(fyne.NewSize(910, 250))
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
sp, vk, ct := loadConfig()
|
|
||||||
if sp != "" && vk != "" && ct != "" {
|
|
||||||
serverPort.SetText(sp)
|
|
||||||
vKey.SetText(vk)
|
|
||||||
connType = ct
|
|
||||||
radio.SetSelected(ct)
|
|
||||||
onclick(sp, vk, ct)
|
|
||||||
}
|
|
||||||
|
|
||||||
return container.NewVBox(
|
|
||||||
widget.NewLabel("Npc "+version.VERSION),
|
|
||||||
serverPort,
|
|
||||||
vKey,
|
|
||||||
radio,
|
|
||||||
button,
|
|
||||||
slo,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
func onclick(s, v, c string) {
|
|
||||||
start = !start
|
|
||||||
if start {
|
|
||||||
closing = false
|
|
||||||
status = "Stop!"
|
|
||||||
// init the npc
|
|
||||||
fmt.Println("submit", s, v, c)
|
|
||||||
sp, vk, ct := loadConfig()
|
|
||||||
if sp != s || vk != v || ct != c {
|
|
||||||
saveConfig(s, v, c)
|
|
||||||
}
|
|
||||||
go func() {
|
|
||||||
for {
|
|
||||||
cl = client.NewRPClient(s, v, c, "", nil, 60)
|
|
||||||
status = "Stop!"
|
|
||||||
refreshCh <- struct{}{}
|
|
||||||
cl.Start()
|
|
||||||
logs.Warn("client closed, reconnecting in 5 seconds...")
|
|
||||||
if closing {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
status = "Reconnecting..."
|
|
||||||
refreshCh <- struct{}{}
|
|
||||||
time.Sleep(time.Second * 5)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
} else {
|
|
||||||
// close the npc
|
|
||||||
status = "Start!"
|
|
||||||
closing = true
|
|
||||||
if cl != nil {
|
|
||||||
go cl.Close()
|
|
||||||
cl = nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
refreshCh <- struct{}{}
|
|
||||||
}
|
|
||||||
|
|
||||||
func getDir() (dir string, err error) {
|
|
||||||
if runtime.GOOS != "android" {
|
|
||||||
dir, err = os.UserConfigDir()
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
dir = "/data/data/org.nps.client/files"
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func saveConfig(host, vkey, connType string) {
|
|
||||||
data := strings.Join([]string{host, vkey, connType}, "\n")
|
|
||||||
ph, err := getDir()
|
|
||||||
if err != nil {
|
|
||||||
logs.Warn("not found config dir")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
_ = os.Remove(path.Join(ph, "npc.conf"))
|
|
||||||
f, err := os.OpenFile(path.Join(ph, "npc.conf"), os.O_CREATE|os.O_WRONLY, 0644)
|
|
||||||
defer f.Close()
|
|
||||||
if err != nil {
|
|
||||||
logs.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if _, err := f.Write([]byte(data)); err != nil {
|
|
||||||
_ = f.Close() // ignore error; Write error takes precedence
|
|
||||||
logs.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func loadConfig() (host, vkey, connType string) {
|
|
||||||
ph, err := getDir()
|
|
||||||
if err != nil {
|
|
||||||
logs.Warn("not found config dir")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
f, err := os.OpenFile(path.Join(ph, "npc.conf"), os.O_RDONLY, 0644)
|
|
||||||
defer f.Close()
|
|
||||||
if err != nil {
|
|
||||||
logs.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
data, err := ioutil.ReadAll(f)
|
|
||||||
if err != nil {
|
|
||||||
logs.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
li := strings.Split(string(data), "\n")
|
|
||||||
host = li[0]
|
|
||||||
vkey = li[1]
|
|
||||||
connType = li[2]
|
|
||||||
return
|
|
||||||
}
|
|
@ -1,821 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
|
||||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
|
||||||
<!-- 由 Microsoft Visio, SVG Export 生成 工作图.svg Page-1 -->
|
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:ev="http://www.w3.org/2001/xml-events"
|
|
||||||
xmlns:v="http://schemas.microsoft.com/visio/2003/SVGExtensions/" width="11.6929in" height="8.26772in"
|
|
||||||
viewBox="0 0 841.89 595.276" xml:space="preserve" color-interpolation-filters="sRGB" class="st17">
|
|
||||||
<v:documentProperties v:langID="2052" v:metric="true" v:viewMarkup="false">
|
|
||||||
<v:userDefs>
|
|
||||||
<v:ud v:nameU="msvNoAutoConnect" v:prompt="" v:val="VT0(0):26"/>
|
|
||||||
</v:userDefs>
|
|
||||||
</v:documentProperties>
|
|
||||||
|
|
||||||
<style type="text/css">
|
|
||||||
<![CDATA[
|
|
||||||
.st1 {fill:#5b9bd5;stroke:#ffffff;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.5}
|
|
||||||
.st2 {stroke:#ffffff;stroke-linecap:butt;stroke-width:0.5}
|
|
||||||
.st3 {fill:#1e4a73;font-family:Calibri;font-size:1.5em}
|
|
||||||
.st4 {fill:#aad288;stroke:#ffffff;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.5}
|
|
||||||
.st5 {fill:#ffffff}
|
|
||||||
.st6 {font-size:1em}
|
|
||||||
.st7 {fill:#5b9bd5}
|
|
||||||
.st8 {stroke:#ffffff;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.5}
|
|
||||||
.st9 {fill:#a5a5a5}
|
|
||||||
.st10 {marker-end:url(#mrkr4-135);marker-start:url(#mrkr4-133);stroke:#5592c9;stroke-linecap:round;stroke-linejoin:round;stroke-width:1.5}
|
|
||||||
.st11 {fill:#5592c9;fill-opacity:1;stroke:#5592c9;stroke-opacity:1;stroke-width:0.37313432835821}
|
|
||||||
.st12 {fill:#ffffff;stroke:none;stroke-linecap:butt;stroke-width:7.2}
|
|
||||||
.st13 {fill:#41729d;font-family:Calibri;font-size:1.5em}
|
|
||||||
.st14 {fill:none;stroke:#42829e;stroke-dasharray:45,27;stroke-linecap:round;stroke-linejoin:round;stroke-width:3}
|
|
||||||
.st15 {fill:none;stroke:none;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.5}
|
|
||||||
.st16 {fill:#5b9bd5;font-family:Calibri;font-size:1.99999em}
|
|
||||||
.st17 {fill:none;fill-rule:evenodd;font-size:12px;overflow:visible;stroke-linecap:square;stroke-miterlimit:3}
|
|
||||||
]]>
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<defs id="Markers">
|
|
||||||
<g id="lend4">
|
|
||||||
<path d="M 2 1 L 0 0 L 2 -1 L 2 1 " style="stroke:none"/>
|
|
||||||
</g>
|
|
||||||
<marker id="mrkr4-133" class="st11" v:arrowType="4" v:arrowSize="2" v:setback="5.12" refX="5.12" orient="auto"
|
|
||||||
markerUnits="strokeWidth" overflow="visible">
|
|
||||||
<use xlink:href="#lend4" transform="scale(2.68) "/>
|
|
||||||
</marker>
|
|
||||||
<marker id="mrkr4-135" class="st11" v:arrowType="4" v:arrowSize="2" v:setback="5.36" refX="-5.36" orient="auto"
|
|
||||||
markerUnits="strokeWidth" overflow="visible">
|
|
||||||
<use xlink:href="#lend4" transform="scale(-2.68,-2.68) "/>
|
|
||||||
</marker>
|
|
||||||
</defs>
|
|
||||||
<g v:mID="0" v:index="1" v:groupContext="foregroundPage">
|
|
||||||
<v:userDefs>
|
|
||||||
<v:ud v:nameU="msvThemeOrder" v:val="VT0(0):26"/>
|
|
||||||
</v:userDefs>
|
|
||||||
<title>页-1</title>
|
|
||||||
<v:pageProperties v:drawingScale="0.0393701" v:pageScale="0.0393701" v:drawingUnits="24" v:shadowOffsetX="8.50394"
|
|
||||||
v:shadowOffsetY="-8.50394"/>
|
|
||||||
<v:layer v:name="连接线" v:index="0"/>
|
|
||||||
<g id="group1-1" transform="translate(418.11,-311.811)" v:mID="1" v:groupContext="group">
|
|
||||||
<v:custProps>
|
|
||||||
<v:cp v:nameU="AssetNumber" v:lbl="资产号" v:prompt="" v:type="0" v:format="" v:sortKey="Asset" v:invis="false"
|
|
||||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
|
||||||
<v:cp v:nameU="SerialNumber" v:lbl="序列号" v:prompt="" v:type="0" v:format="" v:sortKey="Asset" v:invis="false"
|
|
||||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
|
||||||
<v:cp v:nameU="Location" v:lbl="位置" v:prompt="" v:type="0" v:format="" v:sortKey="Asset" v:invis="false"
|
|
||||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
|
||||||
<v:cp v:nameU="Building" v:lbl="构建" v:prompt="" v:type="0" v:format="" v:sortKey="Asset" v:invis="false"
|
|
||||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
|
||||||
<v:cp v:nameU="Room" v:lbl="空间" v:prompt="" v:type="0" v:format="" v:sortKey="Asset" v:invis="false" v:ask="false"
|
|
||||||
v:langID="2052" v:cal="0"/>
|
|
||||||
<v:cp v:nameU="Manufacturer" v:lbl="制造商" v:prompt="" v:type="0" v:format="" v:sortKey="Equipment" v:invis="false"
|
|
||||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
|
||||||
<v:cp v:nameU="ProductNumber" v:lbl="产品编号" v:prompt="" v:type="0" v:format="" v:sortKey="Equipment" v:invis="false"
|
|
||||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
|
||||||
<v:cp v:nameU="PartNumber" v:lbl="部件号" v:prompt="" v:type="0" v:format="" v:sortKey="Equipment" v:invis="false"
|
|
||||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
|
||||||
<v:cp v:nameU="ProductDescription" v:lbl="产品说明" v:prompt="" v:type="0" v:format="" v:sortKey="Equipment"
|
|
||||||
v:invis="false" v:ask="false" v:langID="2052" v:cal="0"/>
|
|
||||||
<v:cp v:nameU="ShapeClass" v:lbl="ShapeClass" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="true"
|
|
||||||
v:ask="false" v:langID="2052" v:cal="0" v:val="VT4(设备)"/>
|
|
||||||
<v:cp v:nameU="ShapeType" v:lbl="ShapeType" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="true"
|
|
||||||
v:ask="false" v:langID="2052" v:cal="0" v:val="VT4(设备)"/>
|
|
||||||
<v:cp v:nameU="SubShapeType" v:lbl="SubShapeType" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="true"
|
|
||||||
v:ask="false" v:langID="2052" v:cal="0" v:val="VT4(防火墙)"/>
|
|
||||||
</v:custProps>
|
|
||||||
<v:userDefs>
|
|
||||||
<v:ud v:nameU="visVersion" v:prompt="" v:val="VT0(15):26"/>
|
|
||||||
<v:ud v:nameU="ShapeClass" v:prompt="" v:val="VT0(5):26"/>
|
|
||||||
<v:ud v:nameU="SolSH" v:prompt="" v:val="VT15({BF0433D9-CD73-4EB5-8390-8653BE590246}):41"/>
|
|
||||||
<v:ud v:nameU="visLegendShape" v:prompt="" v:val="VT0(2):26"/>
|
|
||||||
</v:userDefs>
|
|
||||||
<title>防火墙</title>
|
|
||||||
<desc>NAT</desc>
|
|
||||||
<g id="shape2-2" v:mID="2" v:groupContext="shape" transform="translate(0.545123,-7.63784)">
|
|
||||||
<title>工作表.2</title>
|
|
||||||
<rect x="0" y="539.685" width="69.7759" height="55.5905" class="st1"/>
|
|
||||||
</g>
|
|
||||||
<g id="shape3-4" v:mID="3" v:groupContext="shape" transform="translate(0.795123,-7.88784)">
|
|
||||||
<title>工作表.3</title>
|
|
||||||
<v:userDefs>
|
|
||||||
<v:ud v:nameU="SurroundingRegionColor" v:prompt="" v:val="VT5(1)"/>
|
|
||||||
<v:ud v:nameU="SurroundingRegionColor" v:prompt="" v:val="VT5(#5b9bd5)"/>
|
|
||||||
</v:userDefs>
|
|
||||||
<path d="M0 587.41 L69.28 587.41" class="st2"/>
|
|
||||||
<path d="M0 579.54 L69.28 579.54" class="st2"/>
|
|
||||||
<path d="M0 571.67 L69.28 571.67" class="st2"/>
|
|
||||||
<path d="M0 563.8 L69.28 563.8" class="st2"/>
|
|
||||||
<path d="M0 555.93 L69.28 555.93" class="st2"/>
|
|
||||||
<path d="M0 548.06 L69.28 548.06" class="st2"/>
|
|
||||||
<path d="M17.32 595.28 L17.32 587.41" class="st2"/>
|
|
||||||
<path d="M34.64 595.28 L34.64 587.41" class="st2"/>
|
|
||||||
<path d="M51.96 595.28 L51.96 587.41" class="st2"/>
|
|
||||||
<path d="M8.66 587.41 L8.66 579.54" class="st2"/>
|
|
||||||
<path d="M25.98 587.41 L25.98 579.54" class="st2"/>
|
|
||||||
<path d="M43.3 587.41 L43.3 579.54" class="st2"/>
|
|
||||||
<path d="M60.62 587.41 L60.62 579.54" class="st2"/>
|
|
||||||
<path d="M17.32 579.54 L17.32 571.67" class="st2"/>
|
|
||||||
<path d="M34.64 579.54 L34.64 571.67" class="st2"/>
|
|
||||||
<path d="M51.96 579.54 L51.96 571.67" class="st2"/>
|
|
||||||
<path d="M8.66 571.67 L8.66 563.8" class="st2"/>
|
|
||||||
<path d="M25.98 571.67 L25.98 563.8" class="st2"/>
|
|
||||||
<path d="M43.3 571.67 L43.3 563.8" class="st2"/>
|
|
||||||
<path d="M60.62 571.67 L60.62 563.8" class="st2"/>
|
|
||||||
<path d="M17.32 563.8 L17.32 555.93" class="st2"/>
|
|
||||||
<path d="M34.64 563.8 L34.64 555.93" class="st2"/>
|
|
||||||
<path d="M51.96 563.8 L51.96 555.93" class="st2"/>
|
|
||||||
<path d="M8.66 555.93 L8.66 548.06" class="st2"/>
|
|
||||||
<path d="M25.98 555.93 L25.98 548.06" class="st2"/>
|
|
||||||
<path d="M43.3 555.93 L43.3 548.06" class="st2"/>
|
|
||||||
<path d="M60.62 555.93 L60.62 548.06" class="st2"/>
|
|
||||||
<path d="M17.32 548.06 L17.32 540.19" class="st2"/>
|
|
||||||
<path d="M34.64 548.06 L34.64 540.19" class="st2"/>
|
|
||||||
<path d="M51.96 548.06 L51.96 540.19" class="st2"/>
|
|
||||||
</g>
|
|
||||||
<g id="shape1-36" v:mID="1" v:groupContext="groupContent">
|
|
||||||
<v:textBlock v:margins="rect(4,4,4,4)" v:tabSpace="42.5197"/>
|
|
||||||
<v:textRect cx="35.4331" cy="610.077" width="42.88" height="29.6036"/>
|
|
||||||
<text x="20.03" y="615.48" class="st3" v:langID="2052"><v:paragraph v:horizAlign="1"/><v:tabList/>NAT</text> </g>
|
|
||||||
</g>
|
|
||||||
<g id="group4-38" transform="translate(701.575,-311.811)" v:mID="4" v:groupContext="group">
|
|
||||||
<v:custProps>
|
|
||||||
<v:cp v:nameU="AssetNumber" v:lbl="资产号" v:prompt="" v:type="0" v:format="" v:sortKey="Asset" v:invis="false"
|
|
||||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
|
||||||
<v:cp v:nameU="SerialNumber" v:lbl="序列号" v:prompt="" v:type="0" v:format="" v:sortKey="Asset" v:invis="false"
|
|
||||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
|
||||||
<v:cp v:nameU="Location" v:lbl="位置" v:prompt="" v:type="0" v:format="" v:sortKey="Asset" v:invis="false"
|
|
||||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
|
||||||
<v:cp v:nameU="Building" v:lbl="构建" v:prompt="" v:type="0" v:format="" v:sortKey="Asset" v:invis="false"
|
|
||||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
|
||||||
<v:cp v:nameU="Room" v:lbl="空间" v:prompt="" v:type="0" v:format="" v:sortKey="Asset" v:invis="false" v:ask="false"
|
|
||||||
v:langID="2052" v:cal="0"/>
|
|
||||||
<v:cp v:nameU="Manufacturer" v:lbl="制造商" v:prompt="" v:type="0" v:format="" v:sortKey="Equipment" v:invis="false"
|
|
||||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
|
||||||
<v:cp v:nameU="ProductNumber" v:lbl="产品编号" v:prompt="" v:type="0" v:format="" v:sortKey="Equipment" v:invis="false"
|
|
||||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
|
||||||
<v:cp v:nameU="PartNumber" v:lbl="部件号" v:prompt="" v:type="0" v:format="" v:sortKey="Equipment" v:invis="false"
|
|
||||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
|
||||||
<v:cp v:nameU="ProductDescription" v:lbl="产品说明" v:prompt="" v:type="0" v:format="" v:sortKey="Equipment"
|
|
||||||
v:invis="false" v:ask="false" v:langID="2052" v:cal="0"/>
|
|
||||||
<v:cp v:nameU="NetworkName" v:lbl="网络名称" v:prompt="" v:type="0" v:format="" v:sortKey="Network" v:invis="false"
|
|
||||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
|
||||||
<v:cp v:nameU="IPAddress" v:lbl="IP 地址" v:prompt="" v:type="0" v:format="" v:sortKey="Network" v:invis="false"
|
|
||||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
|
||||||
<v:cp v:nameU="SubnetMask" v:lbl="子网掩码" v:prompt="" v:type="0" v:format="" v:sortKey="Network" v:invis="false"
|
|
||||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
|
||||||
<v:cp v:nameU="AdminInterface" v:lbl="管理接口" v:prompt="" v:type="0" v:format="" v:sortKey="Network" v:invis="false"
|
|
||||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
|
||||||
<v:cp v:nameU="NumberofPorts" v:lbl="端口数目" v:prompt="" v:type="0" v:format="" v:sortKey="Network" v:invis="false"
|
|
||||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
|
||||||
<v:cp v:nameU="CommunityString" v:lbl="团体字符串" v:prompt="" v:type="0" v:format="" v:sortKey="Network"
|
|
||||||
v:invis="false" v:ask="false" v:langID="2052" v:cal="0"/>
|
|
||||||
<v:cp v:nameU="NetworkDescription" v:lbl="网络说明" v:prompt="" v:type="0" v:format="" v:sortKey="Network"
|
|
||||||
v:invis="false" v:ask="false" v:langID="2052" v:cal="0"/>
|
|
||||||
<v:cp v:nameU="MACAddress" v:lbl="MAC 地址" v:prompt="" v:type="0" v:format="" v:sortKey="Network" v:invis="false"
|
|
||||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
|
||||||
<v:cp v:nameU="CPU" v:lbl="CPU" v:prompt="" v:type="0" v:format="" v:sortKey="Workstation" v:invis="false"
|
|
||||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
|
||||||
<v:cp v:nameU="Memory" v:lbl="内存" v:prompt="" v:type="0" v:format="" v:sortKey="Workstation" v:invis="false"
|
|
||||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
|
||||||
<v:cp v:nameU="OperatingSystem" v:lbl="操作系统" v:prompt="" v:type="0" v:format="" v:sortKey="Workstation"
|
|
||||||
v:invis="false" v:ask="false" v:langID="2052" v:cal="0"/>
|
|
||||||
<v:cp v:nameU="HardDriveSize" v:lbl="硬盘容量" v:prompt="" v:type="0" v:format="" v:sortKey="Workstation"
|
|
||||||
v:invis="false" v:ask="false" v:langID="2052" v:cal="0"/>
|
|
||||||
<v:cp v:nameU="Department" v:lbl="部门" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="false" v:ask="false"
|
|
||||||
v:langID="2052" v:cal="0"/>
|
|
||||||
<v:cp v:nameU="ShapeClass" v:lbl="ShapeClass" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="true"
|
|
||||||
v:ask="false" v:langID="2052" v:cal="0" v:val="VT4(设备)"/>
|
|
||||||
<v:cp v:nameU="ShapeType" v:lbl="ShapeType" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="true"
|
|
||||||
v:ask="false" v:langID="2052" v:cal="0" v:val="VT4(服务器)"/>
|
|
||||||
<v:cp v:nameU="BelongsTo" v:lbl="属于" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="true" v:ask="false"
|
|
||||||
v:langID="2052" v:cal="0"/>
|
|
||||||
</v:custProps>
|
|
||||||
<v:userDefs>
|
|
||||||
<v:ud v:nameU="visVersion" v:prompt="" v:val="VT0(15):26"/>
|
|
||||||
<v:ud v:nameU="ShapeClass" v:prompt="" v:val="VT0(5):26"/>
|
|
||||||
<v:ud v:nameU="SolSH" v:prompt="" v:val="VT15({BF0433D9-CD73-4EB5-8390-8653BE590246}):41"/>
|
|
||||||
<v:ud v:nameU="visLegendShape" v:prompt="" v:val="VT0(2):26"/>
|
|
||||||
</v:userDefs>
|
|
||||||
<title>服务器</title>
|
|
||||||
<desc>Application2 10.0.0.4:PORT</desc>
|
|
||||||
<g id="shape5-39" v:mID="5" v:groupContext="shape" transform="translate(12.8133,0)">
|
|
||||||
<title>工作表.5</title>
|
|
||||||
<rect x="0" y="524.409" width="45.2395" height="70.8661" class="st1"/>
|
|
||||||
</g>
|
|
||||||
<g id="shape6-41" v:mID="6" v:groupContext="shape" transform="translate(46.625,-30.2513)">
|
|
||||||
<title>工作表.6</title>
|
|
||||||
<ellipse cx="2.73472" cy="592.541" rx="2.73472" ry="2.73472" class="st4"/>
|
|
||||||
</g>
|
|
||||||
<g id="shape7-43" v:mID="7" v:groupContext="shape" transform="translate(30.0295,-11.6164)">
|
|
||||||
<title>工作表.7</title>
|
|
||||||
<v:userDefs>
|
|
||||||
<v:ud v:nameU="SurroundingRegionColor" v:prompt="" v:val="VT5(1)"/>
|
|
||||||
<v:ud v:nameU="SurroundingRegionColor" v:prompt="" v:val="VT5(#5b9bd5)"/>
|
|
||||||
</v:userDefs>
|
|
||||||
<path d="M-0 595.28 L22.06 595.28 L22.06 593.5 L-0 593.5 L-0 595.28 ZM-0 589.9 L22.06 589.9 L22.06 588.13 L-0 588.13
|
|
||||||
L-0 589.9 ZM-0 584.53 L22.06 584.53 L22.06 582.76 L-0 582.76 L-0 584.53 Z" class="st5"/>
|
|
||||||
</g>
|
|
||||||
<g id="shape4-46" v:mID="4" v:groupContext="groupContent">
|
|
||||||
<v:textBlock v:margins="rect(4,4,4,4)" v:tabSpace="42.5197"/>
|
|
||||||
<v:textRect cx="35.4331" cy="620.877" width="115.9" height="51.2036"/>
|
|
||||||
<text x="-10.6" y="615.48" class="st3" v:langID="2052"><v:paragraph v:horizAlign="1"/><v:tabList/>Application2<v:newlineChar/><tspan
|
|
||||||
x="-16.48" dy="1.2em" class="st6">10.0.0.4:PORT</tspan></text> </g>
|
|
||||||
</g>
|
|
||||||
<g id="group8-49" transform="translate(701.575,-496.063)" v:mID="8" v:groupContext="group">
|
|
||||||
<v:custProps>
|
|
||||||
<v:cp v:nameU="AssetNumber" v:lbl="资产号" v:prompt="" v:type="0" v:format="" v:sortKey="Asset" v:invis="false"
|
|
||||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
|
||||||
<v:cp v:nameU="SerialNumber" v:lbl="序列号" v:prompt="" v:type="0" v:format="" v:sortKey="Asset" v:invis="false"
|
|
||||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
|
||||||
<v:cp v:nameU="Location" v:lbl="位置" v:prompt="" v:type="0" v:format="" v:sortKey="Asset" v:invis="false"
|
|
||||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
|
||||||
<v:cp v:nameU="Building" v:lbl="构建" v:prompt="" v:type="0" v:format="" v:sortKey="Asset" v:invis="false"
|
|
||||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
|
||||||
<v:cp v:nameU="Room" v:lbl="空间" v:prompt="" v:type="0" v:format="" v:sortKey="Asset" v:invis="false" v:ask="false"
|
|
||||||
v:langID="2052" v:cal="0"/>
|
|
||||||
<v:cp v:nameU="Manufacturer" v:lbl="制造商" v:prompt="" v:type="0" v:format="" v:sortKey="Equipment" v:invis="false"
|
|
||||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
|
||||||
<v:cp v:nameU="ProductNumber" v:lbl="产品编号" v:prompt="" v:type="0" v:format="" v:sortKey="Equipment" v:invis="false"
|
|
||||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
|
||||||
<v:cp v:nameU="PartNumber" v:lbl="部件号" v:prompt="" v:type="0" v:format="" v:sortKey="Equipment" v:invis="false"
|
|
||||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
|
||||||
<v:cp v:nameU="ProductDescription" v:lbl="产品说明" v:prompt="" v:type="0" v:format="" v:sortKey="Equipment"
|
|
||||||
v:invis="false" v:ask="false" v:langID="2052" v:cal="0"/>
|
|
||||||
<v:cp v:nameU="NetworkName" v:lbl="网络名称" v:prompt="" v:type="0" v:format="" v:sortKey="Network" v:invis="false"
|
|
||||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
|
||||||
<v:cp v:nameU="IPAddress" v:lbl="IP 地址" v:prompt="" v:type="0" v:format="" v:sortKey="Network" v:invis="false"
|
|
||||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
|
||||||
<v:cp v:nameU="SubnetMask" v:lbl="子网掩码" v:prompt="" v:type="0" v:format="" v:sortKey="Network" v:invis="false"
|
|
||||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
|
||||||
<v:cp v:nameU="AdminInterface" v:lbl="管理接口" v:prompt="" v:type="0" v:format="" v:sortKey="Network" v:invis="false"
|
|
||||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
|
||||||
<v:cp v:nameU="NumberofPorts" v:lbl="端口数目" v:prompt="" v:type="0" v:format="" v:sortKey="Network" v:invis="false"
|
|
||||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
|
||||||
<v:cp v:nameU="CommunityString" v:lbl="团体字符串" v:prompt="" v:type="0" v:format="" v:sortKey="Network"
|
|
||||||
v:invis="false" v:ask="false" v:langID="2052" v:cal="0"/>
|
|
||||||
<v:cp v:nameU="NetworkDescription" v:lbl="网络说明" v:prompt="" v:type="0" v:format="" v:sortKey="Network"
|
|
||||||
v:invis="false" v:ask="false" v:langID="2052" v:cal="0"/>
|
|
||||||
<v:cp v:nameU="MACAddress" v:lbl="MAC 地址" v:prompt="" v:type="0" v:format="" v:sortKey="Network" v:invis="false"
|
|
||||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
|
||||||
<v:cp v:nameU="CPU" v:lbl="CPU" v:prompt="" v:type="0" v:format="" v:sortKey="Workstation" v:invis="false"
|
|
||||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
|
||||||
<v:cp v:nameU="Memory" v:lbl="内存" v:prompt="" v:type="0" v:format="" v:sortKey="Workstation" v:invis="false"
|
|
||||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
|
||||||
<v:cp v:nameU="OperatingSystem" v:lbl="操作系统" v:prompt="" v:type="0" v:format="" v:sortKey="Workstation"
|
|
||||||
v:invis="false" v:ask="false" v:langID="2052" v:cal="0"/>
|
|
||||||
<v:cp v:nameU="HardDriveSize" v:lbl="硬盘容量" v:prompt="" v:type="0" v:format="" v:sortKey="Workstation"
|
|
||||||
v:invis="false" v:ask="false" v:langID="2052" v:cal="0"/>
|
|
||||||
<v:cp v:nameU="Department" v:lbl="部门" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="false" v:ask="false"
|
|
||||||
v:langID="2052" v:cal="0"/>
|
|
||||||
<v:cp v:nameU="ShapeClass" v:lbl="ShapeClass" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="true"
|
|
||||||
v:ask="false" v:langID="2052" v:cal="0" v:val="VT4(设备)"/>
|
|
||||||
<v:cp v:nameU="ShapeType" v:lbl="ShapeType" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="true"
|
|
||||||
v:ask="false" v:langID="2052" v:cal="0" v:val="VT4(服务器)"/>
|
|
||||||
<v:cp v:nameU="BelongsTo" v:lbl="属于" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="true" v:ask="false"
|
|
||||||
v:langID="2052" v:cal="0"/>
|
|
||||||
</v:custProps>
|
|
||||||
<v:userDefs>
|
|
||||||
<v:ud v:nameU="visVersion" v:prompt="" v:val="VT0(15):26"/>
|
|
||||||
<v:ud v:nameU="ShapeClass" v:prompt="" v:val="VT0(5):26"/>
|
|
||||||
<v:ud v:nameU="SolSH" v:prompt="" v:val="VT15({BF0433D9-CD73-4EB5-8390-8653BE590246}):41"/>
|
|
||||||
<v:ud v:nameU="visLegendShape" v:prompt="" v:val="VT0(2):26"/>
|
|
||||||
</v:userDefs>
|
|
||||||
<title>服务器.8</title>
|
|
||||||
<desc>Application1 10.0.0.3:PORT</desc>
|
|
||||||
<g id="shape9-50" v:mID="9" v:groupContext="shape" transform="translate(12.8133,0)">
|
|
||||||
<title>工作表.9</title>
|
|
||||||
<rect x="0" y="524.409" width="45.2395" height="70.8661" class="st1"/>
|
|
||||||
</g>
|
|
||||||
<g id="shape10-52" v:mID="10" v:groupContext="shape" transform="translate(46.625,-30.2513)">
|
|
||||||
<title>工作表.10</title>
|
|
||||||
<ellipse cx="2.73472" cy="592.541" rx="2.73472" ry="2.73472" class="st4"/>
|
|
||||||
</g>
|
|
||||||
<g id="shape11-54" v:mID="11" v:groupContext="shape" transform="translate(30.0295,-11.6164)">
|
|
||||||
<title>工作表.11</title>
|
|
||||||
<v:userDefs>
|
|
||||||
<v:ud v:nameU="SurroundingRegionColor" v:prompt="" v:val="VT5(1)"/>
|
|
||||||
<v:ud v:nameU="SurroundingRegionColor" v:prompt="" v:val="VT5(#5b9bd5)"/>
|
|
||||||
</v:userDefs>
|
|
||||||
<path d="M-0 595.28 L22.06 595.28 L22.06 593.5 L-0 593.5 L-0 595.28 ZM-0 589.9 L22.06 589.9 L22.06 588.13 L-0 588.13
|
|
||||||
L-0 589.9 ZM-0 584.53 L22.06 584.53 L22.06 582.76 L-0 582.76 L-0 584.53 Z" class="st5"/>
|
|
||||||
</g>
|
|
||||||
<g id="shape8-57" v:mID="8" v:groupContext="groupContent">
|
|
||||||
<v:textBlock v:margins="rect(4,4,4,4)" v:tabSpace="42.5197"/>
|
|
||||||
<v:textRect cx="35.4331" cy="620.877" width="115.9" height="51.2036"/>
|
|
||||||
<text x="-10.6" y="615.48" class="st3" v:langID="2052"><v:paragraph v:horizAlign="1"/><v:tabList/>Application1<v:newlineChar/><tspan
|
|
||||||
x="-16.48" dy="1.2em" class="st6">10.0.0.3:PORT</tspan></text> </g>
|
|
||||||
</g>
|
|
||||||
<g id="group12-60" transform="translate(701.575,-127.559)" v:mID="12" v:groupContext="group">
|
|
||||||
<v:custProps>
|
|
||||||
<v:cp v:nameU="AssetNumber" v:lbl="资产号" v:prompt="" v:type="0" v:format="" v:sortKey="Asset" v:invis="false"
|
|
||||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
|
||||||
<v:cp v:nameU="SerialNumber" v:lbl="序列号" v:prompt="" v:type="0" v:format="" v:sortKey="Asset" v:invis="false"
|
|
||||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
|
||||||
<v:cp v:nameU="Location" v:lbl="位置" v:prompt="" v:type="0" v:format="" v:sortKey="Asset" v:invis="false"
|
|
||||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
|
||||||
<v:cp v:nameU="Building" v:lbl="构建" v:prompt="" v:type="0" v:format="" v:sortKey="Asset" v:invis="false"
|
|
||||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
|
||||||
<v:cp v:nameU="Room" v:lbl="空间" v:prompt="" v:type="0" v:format="" v:sortKey="Asset" v:invis="false" v:ask="false"
|
|
||||||
v:langID="2052" v:cal="0"/>
|
|
||||||
<v:cp v:nameU="Manufacturer" v:lbl="制造商" v:prompt="" v:type="0" v:format="" v:sortKey="Equipment" v:invis="false"
|
|
||||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
|
||||||
<v:cp v:nameU="ProductNumber" v:lbl="产品编号" v:prompt="" v:type="0" v:format="" v:sortKey="Equipment" v:invis="false"
|
|
||||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
|
||||||
<v:cp v:nameU="PartNumber" v:lbl="部件号" v:prompt="" v:type="0" v:format="" v:sortKey="Equipment" v:invis="false"
|
|
||||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
|
||||||
<v:cp v:nameU="ProductDescription" v:lbl="产品说明" v:prompt="" v:type="0" v:format="" v:sortKey="Equipment"
|
|
||||||
v:invis="false" v:ask="false" v:langID="2052" v:cal="0"/>
|
|
||||||
<v:cp v:nameU="NetworkName" v:lbl="网络名称" v:prompt="" v:type="0" v:format="" v:sortKey="Network" v:invis="false"
|
|
||||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
|
||||||
<v:cp v:nameU="IPAddress" v:lbl="IP 地址" v:prompt="" v:type="0" v:format="" v:sortKey="Network" v:invis="false"
|
|
||||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
|
||||||
<v:cp v:nameU="SubnetMask" v:lbl="子网掩码" v:prompt="" v:type="0" v:format="" v:sortKey="Network" v:invis="false"
|
|
||||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
|
||||||
<v:cp v:nameU="AdminInterface" v:lbl="管理接口" v:prompt="" v:type="0" v:format="" v:sortKey="Network" v:invis="false"
|
|
||||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
|
||||||
<v:cp v:nameU="NumberofPorts" v:lbl="端口数目" v:prompt="" v:type="0" v:format="" v:sortKey="Network" v:invis="false"
|
|
||||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
|
||||||
<v:cp v:nameU="CommunityString" v:lbl="团体字符串" v:prompt="" v:type="0" v:format="" v:sortKey="Network"
|
|
||||||
v:invis="false" v:ask="false" v:langID="2052" v:cal="0"/>
|
|
||||||
<v:cp v:nameU="NetworkDescription" v:lbl="网络说明" v:prompt="" v:type="0" v:format="" v:sortKey="Network"
|
|
||||||
v:invis="false" v:ask="false" v:langID="2052" v:cal="0"/>
|
|
||||||
<v:cp v:nameU="MACAddress" v:lbl="MAC 地址" v:prompt="" v:type="0" v:format="" v:sortKey="Network" v:invis="false"
|
|
||||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
|
||||||
<v:cp v:nameU="CPU" v:lbl="CPU" v:prompt="" v:type="0" v:format="" v:sortKey="Workstation" v:invis="false"
|
|
||||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
|
||||||
<v:cp v:nameU="Memory" v:lbl="内存" v:prompt="" v:type="0" v:format="" v:sortKey="Workstation" v:invis="false"
|
|
||||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
|
||||||
<v:cp v:nameU="OperatingSystem" v:lbl="操作系统" v:prompt="" v:type="0" v:format="" v:sortKey="Workstation"
|
|
||||||
v:invis="false" v:ask="false" v:langID="2052" v:cal="0"/>
|
|
||||||
<v:cp v:nameU="HardDriveSize" v:lbl="硬盘容量" v:prompt="" v:type="0" v:format="" v:sortKey="Workstation"
|
|
||||||
v:invis="false" v:ask="false" v:langID="2052" v:cal="0"/>
|
|
||||||
<v:cp v:nameU="Department" v:lbl="部门" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="false" v:ask="false"
|
|
||||||
v:langID="2052" v:cal="0"/>
|
|
||||||
<v:cp v:nameU="ShapeClass" v:lbl="ShapeClass" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="true"
|
|
||||||
v:ask="false" v:langID="2052" v:cal="0" v:val="VT4(设备)"/>
|
|
||||||
<v:cp v:nameU="ShapeType" v:lbl="ShapeType" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="true"
|
|
||||||
v:ask="false" v:langID="2052" v:cal="0" v:val="VT4(服务器)"/>
|
|
||||||
<v:cp v:nameU="BelongsTo" v:lbl="属于" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="true" v:ask="false"
|
|
||||||
v:langID="2052" v:cal="0"/>
|
|
||||||
</v:custProps>
|
|
||||||
<v:userDefs>
|
|
||||||
<v:ud v:nameU="visVersion" v:prompt="" v:val="VT0(15):26"/>
|
|
||||||
<v:ud v:nameU="ShapeClass" v:prompt="" v:val="VT0(5):26"/>
|
|
||||||
<v:ud v:nameU="SolSH" v:prompt="" v:val="VT15({BF0433D9-CD73-4EB5-8390-8653BE590246}):41"/>
|
|
||||||
<v:ud v:nameU="visLegendShape" v:prompt="" v:val="VT0(2):26"/>
|
|
||||||
</v:userDefs>
|
|
||||||
<title>服务器.12</title>
|
|
||||||
<desc>Application3 10.0.0.5:PORT</desc>
|
|
||||||
<g id="shape13-61" v:mID="13" v:groupContext="shape" transform="translate(12.8133,0)">
|
|
||||||
<title>工作表.13</title>
|
|
||||||
<rect x="0" y="524.409" width="45.2395" height="70.8661" class="st1"/>
|
|
||||||
</g>
|
|
||||||
<g id="shape14-63" v:mID="14" v:groupContext="shape" transform="translate(46.625,-30.2513)">
|
|
||||||
<title>工作表.14</title>
|
|
||||||
<ellipse cx="2.73472" cy="592.541" rx="2.73472" ry="2.73472" class="st4"/>
|
|
||||||
</g>
|
|
||||||
<g id="shape15-65" v:mID="15" v:groupContext="shape" transform="translate(30.0295,-11.6164)">
|
|
||||||
<title>工作表.15</title>
|
|
||||||
<v:userDefs>
|
|
||||||
<v:ud v:nameU="SurroundingRegionColor" v:prompt="" v:val="VT5(1)"/>
|
|
||||||
<v:ud v:nameU="SurroundingRegionColor" v:prompt="" v:val="VT5(#5b9bd5)"/>
|
|
||||||
</v:userDefs>
|
|
||||||
<path d="M-0 595.28 L22.06 595.28 L22.06 593.5 L-0 593.5 L-0 595.28 ZM-0 589.9 L22.06 589.9 L22.06 588.13 L-0 588.13
|
|
||||||
L-0 589.9 ZM-0 584.53 L22.06 584.53 L22.06 582.76 L-0 582.76 L-0 584.53 Z" class="st5"/>
|
|
||||||
</g>
|
|
||||||
<g id="shape12-68" v:mID="12" v:groupContext="groupContent">
|
|
||||||
<v:textBlock v:margins="rect(4,4,4,4)" v:tabSpace="42.5197"/>
|
|
||||||
<v:textRect cx="35.4331" cy="620.877" width="115.9" height="51.2036"/>
|
|
||||||
<text x="-10.6" y="615.48" class="st3" v:langID="2052"><v:paragraph v:horizAlign="1"/><v:tabList/>Application3<v:newlineChar/><tspan
|
|
||||||
x="-16.48" dy="1.2em" class="st6">10.0.0.5:PORT</tspan></text> </g>
|
|
||||||
</g>
|
|
||||||
<g id="group16-71" transform="translate(538.583,-311.811)" v:mID="16" v:groupContext="group">
|
|
||||||
<v:custProps>
|
|
||||||
<v:cp v:nameU="AssetNumber" v:lbl="资产号" v:prompt="" v:type="0" v:format="" v:sortKey="Asset" v:invis="false"
|
|
||||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
|
||||||
<v:cp v:nameU="SerialNumber" v:lbl="序列号" v:prompt="" v:type="0" v:format="" v:sortKey="Asset" v:invis="false"
|
|
||||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
|
||||||
<v:cp v:nameU="Location" v:lbl="位置" v:prompt="" v:type="0" v:format="" v:sortKey="Asset" v:invis="false"
|
|
||||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
|
||||||
<v:cp v:nameU="Building" v:lbl="建筑物" v:prompt="" v:type="0" v:format="" v:sortKey="Asset" v:invis="false"
|
|
||||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
|
||||||
<v:cp v:nameU="Room" v:lbl="空间" v:prompt="" v:type="0" v:format="" v:sortKey="Asset" v:invis="false" v:ask="false"
|
|
||||||
v:langID="2052" v:cal="0"/>
|
|
||||||
<v:cp v:nameU="Manufacturer" v:lbl="制造商" v:prompt="" v:type="0" v:format="" v:sortKey="Equipment" v:invis="false"
|
|
||||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
|
||||||
<v:cp v:nameU="ProductNumber" v:lbl="产品编号" v:prompt="" v:type="0" v:format="" v:sortKey="Equipment" v:invis="false"
|
|
||||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
|
||||||
<v:cp v:nameU="PartNumber" v:lbl="部件号" v:prompt="" v:type="0" v:format="" v:sortKey="Equipment" v:invis="false"
|
|
||||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
|
||||||
<v:cp v:nameU="ProductDescription" v:lbl="产品说明" v:prompt="" v:type="0" v:format="" v:sortKey="Equipment"
|
|
||||||
v:invis="false" v:ask="false" v:langID="2052" v:cal="0"/>
|
|
||||||
<v:cp v:nameU="NetworkName" v:lbl="网络名称" v:prompt="" v:type="0" v:format="" v:sortKey="Network" v:invis="false"
|
|
||||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
|
||||||
<v:cp v:nameU="IPAddress" v:lbl="IP 地址" v:prompt="" v:type="0" v:format="" v:sortKey="Network" v:invis="false"
|
|
||||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
|
||||||
<v:cp v:nameU="SubnetMask" v:lbl="子网掩码" v:prompt="" v:type="0" v:format="" v:sortKey="Network" v:invis="false"
|
|
||||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
|
||||||
<v:cp v:nameU="AdminInterface" v:lbl="管理接口" v:prompt="" v:type="0" v:format="" v:sortKey="Network" v:invis="false"
|
|
||||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
|
||||||
<v:cp v:nameU="NumberofPorts" v:lbl="端口数目" v:prompt="" v:type="0" v:format="" v:sortKey="Network" v:invis="false"
|
|
||||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
|
||||||
<v:cp v:nameU="CommunityString" v:lbl="团体字符串" v:prompt="" v:type="0" v:format="" v:sortKey="Network"
|
|
||||||
v:invis="false" v:ask="false" v:langID="2052" v:cal="0"/>
|
|
||||||
<v:cp v:nameU="NetworkDescription" v:lbl="网络说明" v:prompt="" v:type="0" v:format="" v:sortKey="Network"
|
|
||||||
v:invis="false" v:ask="false" v:langID="2052" v:cal="0"/>
|
|
||||||
<v:cp v:nameU="MACAddress" v:lbl="MAC 地址" v:prompt="" v:type="0" v:format="" v:sortKey="Network" v:invis="false"
|
|
||||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
|
||||||
<v:cp v:nameU="ShapeClass" v:lbl="ShapeClass" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="true"
|
|
||||||
v:ask="false" v:langID="2052" v:cal="0" v:val="VT4(设备)"/>
|
|
||||||
<v:cp v:nameU="ShapeType" v:lbl="ShapeType" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="true"
|
|
||||||
v:ask="false" v:langID="2052" v:cal="0" v:val="VT4(计算机)"/>
|
|
||||||
<v:cp v:nameU="SubShapeType" v:lbl="SubShapeType" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="true"
|
|
||||||
v:ask="false" v:langID="2052" v:cal="0" v:val="VT4(大型机)"/>
|
|
||||||
</v:custProps>
|
|
||||||
<v:userDefs>
|
|
||||||
<v:ud v:nameU="visVersion" v:prompt="" v:val="VT0(15):26"/>
|
|
||||||
<v:ud v:nameU="ShapeClass" v:prompt="" v:val="VT0(5):26"/>
|
|
||||||
<v:ud v:nameU="SolSH" v:prompt="" v:val="VT15({BF0433D9-CD73-4EB5-8390-8653BE590246}):41"/>
|
|
||||||
<v:ud v:nameU="visLegendShape" v:prompt="" v:val="VT0(2):26"/>
|
|
||||||
</v:userDefs>
|
|
||||||
<title>主机</title>
|
|
||||||
<desc>NPC Client 10.0.0.2 Dial To: ->10.0.0.3:PORT ->10.0.0.4:PORT ...</desc>
|
|
||||||
<g id="shape17-72" v:mID="17" v:groupContext="shape" transform="translate(5.68158,0)">
|
|
||||||
<title>工作表.17</title>
|
|
||||||
<path d="M0 595.28 L59.5 595.28 L59.5 524.41 L0 524.41 L0 595.28 Z" class="st7"/>
|
|
||||||
<path d="M0 595.28 L59.5 595.28 L59.5 524.41 L0 524.41 L0 595.28" class="st8"/>
|
|
||||||
<path d="M29.75 595.28 L29.75 524.41" class="st8"/>
|
|
||||||
</g>
|
|
||||||
<g id="shape18-76" v:mID="18" v:groupContext="shape" transform="translate(11.5726,-5.14536)">
|
|
||||||
<title>工作表.18</title>
|
|
||||||
<v:userDefs>
|
|
||||||
<v:ud v:nameU="SurroundingRegionColor" v:prompt="" v:val="VT5(1)"/>
|
|
||||||
<v:ud v:nameU="SurroundingRegionColor" v:prompt="" v:val="VT5(#5b9bd5)"/>
|
|
||||||
</v:userDefs>
|
|
||||||
<path d="M36.09 551.42 L49.23 551.42 L49.23 536.38 L36.09 536.38 L36.09 551.42 ZM14.89 542.47 L16.68 542.47 L16.68
|
|
||||||
536.06 L14.89 536.06 L14.89 542.47 ZM14.89 551.71 L16.68 551.71 L16.68 545.3 L14.89 545.3 L14.89 551.71
|
|
||||||
ZM10.63 542.47 L12.43 542.47 L12.43 536.06 L10.63 536.06 L10.63 542.47 ZM10.63 551.71 L12.43 551.71
|
|
||||||
L12.43 545.3 L10.63 545.3 L10.63 551.71 ZM4.25 542.47 L6.05 542.47 L6.05 536.06 L4.25 536.06 L4.25 542.47
|
|
||||||
ZM4.25 551.71 L6.05 551.71 L6.05 545.3 L4.25 545.3 L4.25 551.71 ZM0 542.47 L1.79 542.47 L1.79 536.06
|
|
||||||
L0 536.06 L0 542.47 ZM0 551.71 L1.79 551.71 L1.79 545.3 L0 545.3 L0 551.71 ZM33.82 586.45 L33.82 587.7
|
|
||||||
L49.39 587.69 L49.39 586.44 L33.82 586.45 ZM33.82 590.24 L33.82 591.49 L49.39 591.48 L49.39 590.24 L33.82
|
|
||||||
590.24 ZM33.82 594.03 L33.82 595.28 L49.39 595.27 L49.39 594.03 L33.82 594.03 ZM2.96 587.7 L18.52 587.7
|
|
||||||
L18.52 586.45 L2.95 586.45 L2.96 587.7 ZM2.96 591.49 L18.52 591.49 L18.52 590.24 L2.95 590.24 L2.96
|
|
||||||
591.49 ZM2.96 595.28 L18.52 595.28 L18.52 594.03 L2.95 594.03 L2.96 595.28 Z" class="st5"/>
|
|
||||||
</g>
|
|
||||||
<g id="shape19-79" v:mID="19" v:groupContext="shape" transform="translate(49.0815,-50.4059)">
|
|
||||||
<title>工作表.19</title>
|
|
||||||
<path d="M8.15 583.79 A1.11073 1.11073 -180 1 0 10.24 584.56 A1.11073 1.11073 -180 1 0 8.15 583.79 ZM8.17 587.08
|
|
||||||
A1.11073 1.11073 -180 1 0 10.22 587.93 A1.11073 1.11073 -180 1 0 8.17 587.08 ZM8.18 590.39 A1.11073
|
|
||||||
1.11073 -180 1 0 10.21 591.28 A1.11073 1.11073 -180 1 0 8.18 590.39 ZM8.18 593.71 A1.11073 1.11073 -180
|
|
||||||
1 0 10.21 594.6 A1.11073 1.11073 -180 1 0 8.18 593.71 ZM4.1 583.84 A1.11073 1.11073 -180 1 0 6.21 584.51
|
|
||||||
A1.11073 1.11073 -180 1 0 4.1 583.84 ZM4.11 587.14 A1.11073 1.11073 -180 1 0 6.2 587.87 A1.11073 1.11073
|
|
||||||
-180 1 0 4.11 587.14 ZM4.11 590.44 A1.11073 1.11073 -180 1 0 6.19 591.22 A1.11073 1.11073 -180 1 0 4.11
|
|
||||||
590.44 ZM4.11 593.77 A1.11073 1.11073 -180 1 0 6.19 594.55 A1.11073 1.11073 -180 1 0 4.11 593.77 ZM0.04
|
|
||||||
583.9 A1.11144 1.11144 -180 1 0 2.19 584.46 A1.11144 1.11144 -180 1 0 0.04 583.9 ZM0.05 587.19 A1.11144
|
|
||||||
1.11144 -180 1 0 2.18 587.82 A1.11144 1.11144 -180 1 0 0.05 587.19 ZM0.05 590.5 A1.11144 1.11144 -180
|
|
||||||
1 0 2.17 591.16 A1.11144 1.11144 -180 1 0 0.05 590.5 ZM0.05 593.83 A1.11144 1.11144 -180 1 0 2.17 594.49
|
|
||||||
A1.11144 1.11144 -180 1 0 0.05 593.83 Z" class="st9"/>
|
|
||||||
</g>
|
|
||||||
<g id="shape16-82" v:mID="16" v:groupContext="groupContent">
|
|
||||||
<v:textBlock v:margins="rect(4,4,4,4)" v:tabSpace="42.5197"/>
|
|
||||||
<v:textRect cx="35.4331" cy="674.877" width="130.38" height="159.204"/>
|
|
||||||
<text x="20.18" y="615.48" class="st3" v:langID="2052"><v:paragraph v:horizAlign="1"/><v:tabList/>NPC<v:newlineChar/><tspan
|
|
||||||
x="14.28" dy="1.2em" class="st6">Client<v:newlineChar/></tspan><tspan x="5.81" dy="1.2em" class="st6">10.0.0.2<v:newlineChar/></tspan><tspan
|
|
||||||
x="7.88" dy="1.2em" class="st6">Dial To:<v:newlineChar/></tspan><tspan x="-23.72" dy="1.2em"
|
|
||||||
class="st6">-</tspan>>10.0.0.3:PORT<v:newlineChar/><tspan x="-23.72" dy="1.2em" class="st6">-</tspan>>10.0.0.4:PORT<v:newlineChar/><tspan
|
|
||||||
x="-23.72" dy="1.2em" class="st6">-</tspan>>10.0.0.5:PORT</text> </g>
|
|
||||||
</g>
|
|
||||||
<g id="group20-90" transform="translate(212.598,-311.811)" v:mID="20" v:groupContext="group">
|
|
||||||
<v:custProps>
|
|
||||||
<v:cp v:nameU="AssetNumber" v:lbl="资产号" v:prompt="" v:type="0" v:format="" v:sortKey="Asset" v:invis="false"
|
|
||||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
|
||||||
<v:cp v:nameU="SerialNumber" v:lbl="序列号" v:prompt="" v:type="0" v:format="" v:sortKey="Asset" v:invis="false"
|
|
||||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
|
||||||
<v:cp v:nameU="Location" v:lbl="位置" v:prompt="" v:type="0" v:format="" v:sortKey="Asset" v:invis="false"
|
|
||||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
|
||||||
<v:cp v:nameU="Building" v:lbl="建筑物" v:prompt="" v:type="0" v:format="" v:sortKey="Asset" v:invis="false"
|
|
||||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
|
||||||
<v:cp v:nameU="Room" v:lbl="空间" v:prompt="" v:type="0" v:format="" v:sortKey="Asset" v:invis="false" v:ask="false"
|
|
||||||
v:langID="2052" v:cal="0"/>
|
|
||||||
<v:cp v:nameU="Manufacturer" v:lbl="制造商" v:prompt="" v:type="0" v:format="" v:sortKey="Equipment" v:invis="false"
|
|
||||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
|
||||||
<v:cp v:nameU="ProductNumber" v:lbl="产品编号" v:prompt="" v:type="0" v:format="" v:sortKey="Equipment" v:invis="false"
|
|
||||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
|
||||||
<v:cp v:nameU="PartNumber" v:lbl="部件号" v:prompt="" v:type="0" v:format="" v:sortKey="Equipment" v:invis="false"
|
|
||||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
|
||||||
<v:cp v:nameU="ProductDescription" v:lbl="产品说明" v:prompt="" v:type="0" v:format="" v:sortKey="Equipment"
|
|
||||||
v:invis="false" v:ask="false" v:langID="2052" v:cal="0"/>
|
|
||||||
<v:cp v:nameU="NetworkName" v:lbl="网络名称" v:prompt="" v:type="0" v:format="" v:sortKey="Network" v:invis="false"
|
|
||||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
|
||||||
<v:cp v:nameU="IPAddress" v:lbl="IP 地址" v:prompt="" v:type="0" v:format="" v:sortKey="Network" v:invis="false"
|
|
||||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
|
||||||
<v:cp v:nameU="SubnetMask" v:lbl="子网掩码" v:prompt="" v:type="0" v:format="" v:sortKey="Network" v:invis="false"
|
|
||||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
|
||||||
<v:cp v:nameU="AdminInterface" v:lbl="管理接口" v:prompt="" v:type="0" v:format="" v:sortKey="Network" v:invis="false"
|
|
||||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
|
||||||
<v:cp v:nameU="NumberofPorts" v:lbl="端口数目" v:prompt="" v:type="0" v:format="" v:sortKey="Network" v:invis="false"
|
|
||||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
|
||||||
<v:cp v:nameU="CommunityString" v:lbl="团体字符串" v:prompt="" v:type="0" v:format="" v:sortKey="Network"
|
|
||||||
v:invis="false" v:ask="false" v:langID="2052" v:cal="0"/>
|
|
||||||
<v:cp v:nameU="NetworkDescription" v:lbl="网络说明" v:prompt="" v:type="0" v:format="" v:sortKey="Network"
|
|
||||||
v:invis="false" v:ask="false" v:langID="2052" v:cal="0"/>
|
|
||||||
<v:cp v:nameU="MACAddress" v:lbl="MAC 地址" v:prompt="" v:type="0" v:format="" v:sortKey="Network" v:invis="false"
|
|
||||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
|
||||||
<v:cp v:nameU="ShapeClass" v:lbl="ShapeClass" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="true"
|
|
||||||
v:ask="false" v:langID="2052" v:cal="0" v:val="VT4(设备)"/>
|
|
||||||
<v:cp v:nameU="ShapeType" v:lbl="ShapeType" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="true"
|
|
||||||
v:ask="false" v:langID="2052" v:cal="0" v:val="VT4(计算机)"/>
|
|
||||||
<v:cp v:nameU="SubShapeType" v:lbl="SubShapeType" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="true"
|
|
||||||
v:ask="false" v:langID="2052" v:cal="0" v:val="VT4(大型机)"/>
|
|
||||||
</v:custProps>
|
|
||||||
<v:userDefs>
|
|
||||||
<v:ud v:nameU="visVersion" v:prompt="" v:val="VT0(15):26"/>
|
|
||||||
<v:ud v:nameU="ShapeClass" v:prompt="" v:val="VT0(5):26"/>
|
|
||||||
<v:ud v:nameU="SolSH" v:prompt="" v:val="VT15({BF0433D9-CD73-4EB5-8390-8653BE590246}):41"/>
|
|
||||||
<v:ud v:nameU="visLegendShape" v:prompt="" v:val="VT0(2):26"/>
|
|
||||||
</v:userDefs>
|
|
||||||
<title>主机.20</title>
|
|
||||||
<desc>NPS Server 1.1.1.1 Listen On: 8003->10.0.0.3:PORT 8004->10.0....</desc>
|
|
||||||
<g id="shape21-91" v:mID="21" v:groupContext="shape" transform="translate(5.68158,0)">
|
|
||||||
<title>工作表.21</title>
|
|
||||||
<path d="M0 595.28 L59.5 595.28 L59.5 524.41 L0 524.41 L0 595.28 Z" class="st7"/>
|
|
||||||
<path d="M0 595.28 L59.5 595.28 L59.5 524.41 L0 524.41 L0 595.28" class="st8"/>
|
|
||||||
<path d="M29.75 595.28 L29.75 524.41" class="st8"/>
|
|
||||||
</g>
|
|
||||||
<g id="shape22-95" v:mID="22" v:groupContext="shape" transform="translate(11.5726,-5.14536)">
|
|
||||||
<title>工作表.22</title>
|
|
||||||
<v:userDefs>
|
|
||||||
<v:ud v:nameU="SurroundingRegionColor" v:prompt="" v:val="VT5(1)"/>
|
|
||||||
<v:ud v:nameU="SurroundingRegionColor" v:prompt="" v:val="VT5(#5b9bd5)"/>
|
|
||||||
</v:userDefs>
|
|
||||||
<path d="M36.09 551.42 L49.23 551.42 L49.23 536.38 L36.09 536.38 L36.09 551.42 ZM14.89 542.47 L16.68 542.47 L16.68
|
|
||||||
536.06 L14.89 536.06 L14.89 542.47 ZM14.89 551.71 L16.68 551.71 L16.68 545.3 L14.89 545.3 L14.89 551.71
|
|
||||||
ZM10.63 542.47 L12.43 542.47 L12.43 536.06 L10.63 536.06 L10.63 542.47 ZM10.63 551.71 L12.43 551.71
|
|
||||||
L12.43 545.3 L10.63 545.3 L10.63 551.71 ZM4.25 542.47 L6.05 542.47 L6.05 536.06 L4.25 536.06 L4.25 542.47
|
|
||||||
ZM4.25 551.71 L6.05 551.71 L6.05 545.3 L4.25 545.3 L4.25 551.71 ZM0 542.47 L1.79 542.47 L1.79 536.06
|
|
||||||
L0 536.06 L0 542.47 ZM0 551.71 L1.79 551.71 L1.79 545.3 L0 545.3 L0 551.71 ZM33.82 586.45 L33.82 587.7
|
|
||||||
L49.39 587.69 L49.39 586.44 L33.82 586.45 ZM33.82 590.24 L33.82 591.49 L49.39 591.48 L49.39 590.24 L33.82
|
|
||||||
590.24 ZM33.82 594.03 L33.82 595.28 L49.39 595.27 L49.39 594.03 L33.82 594.03 ZM2.96 587.7 L18.52 587.7
|
|
||||||
L18.52 586.45 L2.95 586.45 L2.96 587.7 ZM2.96 591.49 L18.52 591.49 L18.52 590.24 L2.95 590.24 L2.96
|
|
||||||
591.49 ZM2.96 595.28 L18.52 595.28 L18.52 594.03 L2.95 594.03 L2.96 595.28 Z" class="st5"/>
|
|
||||||
</g>
|
|
||||||
<g id="shape23-98" v:mID="23" v:groupContext="shape" transform="translate(49.0815,-50.4059)">
|
|
||||||
<title>工作表.23</title>
|
|
||||||
<path d="M8.15 583.79 A1.11073 1.11073 -180 1 0 10.24 584.56 A1.11073 1.11073 -180 1 0 8.15 583.79 ZM8.17 587.08
|
|
||||||
A1.11073 1.11073 -180 1 0 10.22 587.93 A1.11073 1.11073 -180 1 0 8.17 587.08 ZM8.18 590.39 A1.11073
|
|
||||||
1.11073 -180 1 0 10.21 591.28 A1.11073 1.11073 -180 1 0 8.18 590.39 ZM8.18 593.71 A1.11073 1.11073 -180
|
|
||||||
1 0 10.21 594.6 A1.11073 1.11073 -180 1 0 8.18 593.71 ZM4.1 583.84 A1.11073 1.11073 -180 1 0 6.21 584.51
|
|
||||||
A1.11073 1.11073 -180 1 0 4.1 583.84 ZM4.11 587.14 A1.11073 1.11073 -180 1 0 6.2 587.87 A1.11073 1.11073
|
|
||||||
-180 1 0 4.11 587.14 ZM4.11 590.44 A1.11073 1.11073 -180 1 0 6.19 591.22 A1.11073 1.11073 -180 1 0 4.11
|
|
||||||
590.44 ZM4.11 593.77 A1.11073 1.11073 -180 1 0 6.19 594.55 A1.11073 1.11073 -180 1 0 4.11 593.77 ZM0.04
|
|
||||||
583.9 A1.11144 1.11144 -180 1 0 2.19 584.46 A1.11144 1.11144 -180 1 0 0.04 583.9 ZM0.05 587.19 A1.11144
|
|
||||||
1.11144 -180 1 0 2.18 587.82 A1.11144 1.11144 -180 1 0 0.05 587.19 ZM0.05 590.5 A1.11144 1.11144 -180
|
|
||||||
1 0 2.17 591.16 A1.11144 1.11144 -180 1 0 0.05 590.5 ZM0.05 593.83 A1.11144 1.11144 -180 1 0 2.17 594.49
|
|
||||||
A1.11144 1.11144 -180 1 0 0.05 593.83 Z" class="st9"/>
|
|
||||||
</g>
|
|
||||||
<g id="shape20-101" v:mID="20" v:groupContext="groupContent">
|
|
||||||
<v:textBlock v:margins="rect(4,4,4,4)" v:tabSpace="42.5197"/>
|
|
||||||
<v:textRect cx="35.4331" cy="674.877" width="166.87" height="159.204"/>
|
|
||||||
<text x="20.84" y="615.48" class="st3" v:langID="2052"><v:paragraph v:horizAlign="1"/><v:tabList/>NPS<v:newlineChar/><tspan
|
|
||||||
x="12" dy="1.2em" class="st6">Server<v:newlineChar/></tspan><tspan x="10.37" dy="1.2em" class="st6">1.1.1.1<v:newlineChar/></tspan><tspan
|
|
||||||
x="-1.29" dy="1.2em" class="st6">Listen On:<v:newlineChar/></tspan><tspan x="-41.96" dy="1.2em"
|
|
||||||
class="st6">8003</tspan>->10.0.0.3:PORT<v:newlineChar/><tspan x="-41.96" dy="1.2em" class="st6">8004</tspan>->10.0.0.4:PORT<v:newlineChar/><tspan
|
|
||||||
x="-41.96" dy="1.2em" class="st6">8005</tspan>->10.0.0.5:PORT</text> </g>
|
|
||||||
</g>
|
|
||||||
<g id="group24-109" transform="translate(49.6063,-496.063)" v:mID="24" v:groupContext="group">
|
|
||||||
<v:custProps>
|
|
||||||
<v:cp v:nameU="Name" v:lbl="名称" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="false" v:ask="false"
|
|
||||||
v:langID="2052" v:cal="0"/>
|
|
||||||
<v:cp v:nameU="Location" v:lbl="位置" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="false" v:ask="false"
|
|
||||||
v:langID="2052" v:cal="0"/>
|
|
||||||
<v:cp v:nameU="Building" v:lbl="构建" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="false" v:ask="false"
|
|
||||||
v:langID="2052" v:cal="0"/>
|
|
||||||
<v:cp v:nameU="Room" v:lbl="空间" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="false" v:ask="false"
|
|
||||||
v:langID="2052" v:cal="0"/>
|
|
||||||
<v:cp v:nameU="Department" v:lbl="部门" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="false" v:ask="false"
|
|
||||||
v:langID="2052" v:cal="0"/>
|
|
||||||
<v:cp v:nameU="ShapeClass" v:lbl="ShapeClass" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="true"
|
|
||||||
v:ask="false" v:langID="2052" v:cal="0" v:val="VT4(连接性)"/>
|
|
||||||
<v:cp v:nameU="ShapeType" v:lbl="ShapeType" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="true"
|
|
||||||
v:ask="false" v:langID="2052" v:cal="0" v:val="VT4(用户)"/>
|
|
||||||
</v:custProps>
|
|
||||||
<v:userDefs>
|
|
||||||
<v:ud v:nameU="visVersion" v:prompt="" v:val="VT0(15):26"/>
|
|
||||||
<v:ud v:nameU="ShapeClass" v:prompt="" v:val="VT0(5):26"/>
|
|
||||||
<v:ud v:nameU="SolSH" v:prompt="" v:val="VT15({BF0433D9-CD73-4EB5-8390-8653BE590246}):41"/>
|
|
||||||
<v:ud v:nameU="visLegendShape" v:prompt="" v:val="VT0(2):26"/>
|
|
||||||
</v:userDefs>
|
|
||||||
<title>用户</title>
|
|
||||||
<desc>User1 Wants:APP1</desc>
|
|
||||||
<g id="shape25-110" v:mID="25" v:groupContext="shape" transform="translate(18.0575,0)">
|
|
||||||
<title>工作表.25</title>
|
|
||||||
<path d="M26.29 533.22 A8.81 8.81 -180 1 0 8.67 533.22 A8.81 8.81 -180 1 0 26.29 533.22 ZM27.58 544.41 L7.17 544.41
|
|
||||||
C3.22 544.41 0 547.62 0 551.58 L0 576.58 L5.59 576.58 L5.59 562.03 L7.45 562.03 L7.45 595.28 L16.55
|
|
||||||
595.28 L16.55 580.42 C16.55 579.9 16.97 579.48 17.48 579.48 C18 579.48 18.42 579.9 18.42 580.42 L18.42
|
|
||||||
595.28 L28.04 595.28 L28.04 561.98 L29.91 561.98 L29.91 576.58 L34.75 576.58 L34.75 551.58 C34.75 547.62
|
|
||||||
31.54 544.41 27.58 544.41 Z" class="st1"/>
|
|
||||||
</g>
|
|
||||||
<g id="shape24-112" v:mID="24" v:groupContext="groupContent">
|
|
||||||
<v:textBlock v:margins="rect(4,4,4,4)" v:tabSpace="42.5197"/>
|
|
||||||
<v:textRect cx="35.4331" cy="620.877" width="102.19" height="51.2036"/>
|
|
||||||
<text x="13.96" y="615.48" class="st3" v:langID="2052"><v:paragraph v:horizAlign="1"/><v:tabList/>User1<v:newlineChar/><tspan
|
|
||||||
x="-9.62" dy="1.2em" class="st6">Wants:APP1</tspan></text> </g>
|
|
||||||
</g>
|
|
||||||
<g id="group26-115" transform="translate(49.6063,-311.811)" v:mID="26" v:groupContext="group">
|
|
||||||
<v:custProps>
|
|
||||||
<v:cp v:nameU="Name" v:lbl="名称" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="false" v:ask="false"
|
|
||||||
v:langID="2052" v:cal="0"/>
|
|
||||||
<v:cp v:nameU="Location" v:lbl="位置" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="false" v:ask="false"
|
|
||||||
v:langID="2052" v:cal="0"/>
|
|
||||||
<v:cp v:nameU="Building" v:lbl="构建" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="false" v:ask="false"
|
|
||||||
v:langID="2052" v:cal="0"/>
|
|
||||||
<v:cp v:nameU="Room" v:lbl="空间" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="false" v:ask="false"
|
|
||||||
v:langID="2052" v:cal="0"/>
|
|
||||||
<v:cp v:nameU="Department" v:lbl="部门" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="false" v:ask="false"
|
|
||||||
v:langID="2052" v:cal="0"/>
|
|
||||||
<v:cp v:nameU="ShapeClass" v:lbl="ShapeClass" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="true"
|
|
||||||
v:ask="false" v:langID="2052" v:cal="0" v:val="VT4(连接性)"/>
|
|
||||||
<v:cp v:nameU="ShapeType" v:lbl="ShapeType" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="true"
|
|
||||||
v:ask="false" v:langID="2052" v:cal="0" v:val="VT4(用户)"/>
|
|
||||||
</v:custProps>
|
|
||||||
<v:userDefs>
|
|
||||||
<v:ud v:nameU="visVersion" v:prompt="" v:val="VT0(15):26"/>
|
|
||||||
<v:ud v:nameU="ShapeClass" v:prompt="" v:val="VT0(5):26"/>
|
|
||||||
<v:ud v:nameU="SolSH" v:prompt="" v:val="VT15({BF0433D9-CD73-4EB5-8390-8653BE590246}):41"/>
|
|
||||||
<v:ud v:nameU="visLegendShape" v:prompt="" v:val="VT0(2):26"/>
|
|
||||||
</v:userDefs>
|
|
||||||
<title>用户.26</title>
|
|
||||||
<desc>User2 Wants:APP2</desc>
|
|
||||||
<g id="shape27-116" v:mID="27" v:groupContext="shape" transform="translate(18.0575,0)">
|
|
||||||
<title>工作表.27</title>
|
|
||||||
<path d="M26.29 533.22 A8.81 8.81 -180 1 0 8.67 533.22 A8.81 8.81 -180 1 0 26.29 533.22 ZM27.58 544.41 L7.17 544.41
|
|
||||||
C3.22 544.41 0 547.62 0 551.58 L0 576.58 L5.59 576.58 L5.59 562.03 L7.45 562.03 L7.45 595.28 L16.55
|
|
||||||
595.28 L16.55 580.42 C16.55 579.9 16.97 579.48 17.48 579.48 C18 579.48 18.42 579.9 18.42 580.42 L18.42
|
|
||||||
595.28 L28.04 595.28 L28.04 561.98 L29.91 561.98 L29.91 576.58 L34.75 576.58 L34.75 551.58 C34.75 547.62
|
|
||||||
31.54 544.41 27.58 544.41 Z" class="st1"/>
|
|
||||||
</g>
|
|
||||||
<g id="shape26-118" v:mID="26" v:groupContext="groupContent">
|
|
||||||
<v:textBlock v:margins="rect(4,4,4,4)" v:tabSpace="42.5197"/>
|
|
||||||
<v:textRect cx="35.4331" cy="620.877" width="102.19" height="51.2036"/>
|
|
||||||
<text x="13.96" y="615.48" class="st3" v:langID="2052"><v:paragraph v:horizAlign="1"/><v:tabList/>User2<v:newlineChar/><tspan
|
|
||||||
x="-9.62" dy="1.2em" class="st6">Wants:APP2</tspan></text> </g>
|
|
||||||
</g>
|
|
||||||
<g id="group28-121" transform="translate(49.6063,-127.559)" v:mID="28" v:groupContext="group">
|
|
||||||
<v:custProps>
|
|
||||||
<v:cp v:nameU="Name" v:lbl="名称" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="false" v:ask="false"
|
|
||||||
v:langID="2052" v:cal="0"/>
|
|
||||||
<v:cp v:nameU="Location" v:lbl="位置" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="false" v:ask="false"
|
|
||||||
v:langID="2052" v:cal="0"/>
|
|
||||||
<v:cp v:nameU="Building" v:lbl="构建" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="false" v:ask="false"
|
|
||||||
v:langID="2052" v:cal="0"/>
|
|
||||||
<v:cp v:nameU="Room" v:lbl="空间" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="false" v:ask="false"
|
|
||||||
v:langID="2052" v:cal="0"/>
|
|
||||||
<v:cp v:nameU="Department" v:lbl="部门" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="false" v:ask="false"
|
|
||||||
v:langID="2052" v:cal="0"/>
|
|
||||||
<v:cp v:nameU="ShapeClass" v:lbl="ShapeClass" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="true"
|
|
||||||
v:ask="false" v:langID="2052" v:cal="0" v:val="VT4(连接性)"/>
|
|
||||||
<v:cp v:nameU="ShapeType" v:lbl="ShapeType" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="true"
|
|
||||||
v:ask="false" v:langID="2052" v:cal="0" v:val="VT4(用户)"/>
|
|
||||||
</v:custProps>
|
|
||||||
<v:userDefs>
|
|
||||||
<v:ud v:nameU="visVersion" v:prompt="" v:val="VT0(15):26"/>
|
|
||||||
<v:ud v:nameU="ShapeClass" v:prompt="" v:val="VT0(5):26"/>
|
|
||||||
<v:ud v:nameU="SolSH" v:prompt="" v:val="VT15({BF0433D9-CD73-4EB5-8390-8653BE590246}):41"/>
|
|
||||||
<v:ud v:nameU="visLegendShape" v:prompt="" v:val="VT0(2):26"/>
|
|
||||||
</v:userDefs>
|
|
||||||
<title>用户.28</title>
|
|
||||||
<desc>User3 Wants:APP3</desc>
|
|
||||||
<g id="shape29-122" v:mID="29" v:groupContext="shape" transform="translate(18.0575,0)">
|
|
||||||
<title>工作表.29</title>
|
|
||||||
<path d="M26.29 533.22 A8.81 8.81 -180 1 0 8.67 533.22 A8.81 8.81 -180 1 0 26.29 533.22 ZM27.58 544.41 L7.17 544.41
|
|
||||||
C3.22 544.41 0 547.62 0 551.58 L0 576.58 L5.59 576.58 L5.59 562.03 L7.45 562.03 L7.45 595.28 L16.55
|
|
||||||
595.28 L16.55 580.42 C16.55 579.9 16.97 579.48 17.48 579.48 C18 579.48 18.42 579.9 18.42 580.42 L18.42
|
|
||||||
595.28 L28.04 595.28 L28.04 561.98 L29.91 561.98 L29.91 576.58 L34.75 576.58 L34.75 551.58 C34.75 547.62
|
|
||||||
31.54 544.41 27.58 544.41 Z" class="st1"/>
|
|
||||||
</g>
|
|
||||||
<g id="shape28-124" v:mID="28" v:groupContext="groupContent">
|
|
||||||
<v:textBlock v:margins="rect(4,4,4,4)" v:tabSpace="42.5197"/>
|
|
||||||
<v:textRect cx="35.4331" cy="620.877" width="102.19" height="51.2036"/>
|
|
||||||
<text x="13.96" y="615.48" class="st3" v:langID="2052"><v:paragraph v:horizAlign="1"/><v:tabList/>User3<v:newlineChar/><tspan
|
|
||||||
x="-9.62" dy="1.2em" class="st6">Wants:APP3</tspan></text> </g>
|
|
||||||
</g>
|
|
||||||
<g id="shape1003-127" v:mID="1003" v:groupContext="shape" v:layerMember="0" transform="translate(99.8466,-514.757)">
|
|
||||||
<title>动态连接线.1003</title>
|
|
||||||
<desc>->8003 Multi Conn</desc>
|
|
||||||
<v:userDefs>
|
|
||||||
<v:ud v:nameU="visVersion" v:prompt="" v:val="VT0(15):26"/>
|
|
||||||
</v:userDefs>
|
|
||||||
<v:textBlock v:margins="rect(4,4,4,4)" v:tabSpace="42.5197"/>
|
|
||||||
<v:textRect cx="56.059" cy="684.836" width="93.29" height="51.2036"/>
|
|
||||||
<path d="M5.09 601.03 L5.33 601.3 L113.11 723.13" class="st10"/>
|
|
||||||
<rect v:rectContext="textBkgnd" x="15.4535" y="663.236" width="81.2109" height="43.1999" class="st12"/>
|
|
||||||
<text x="30.58" y="679.44" class="st13" v:langID="2052"><v:paragraph v:horizAlign="1"/><v:tabList/>->8003<v:newlineChar/><tspan
|
|
||||||
x="15.45" dy="1.2em" class="st6">Multi Conn</tspan></text> </g>
|
|
||||||
<g id="shape1004-139" v:mID="1004" v:groupContext="shape" v:layerMember="0" transform="translate(102.415,-340.157)">
|
|
||||||
<title>动态连接线.1004</title>
|
|
||||||
<desc>->8004 Multi Conn</desc>
|
|
||||||
<v:userDefs>
|
|
||||||
<v:ud v:nameU="visVersion" v:prompt="" v:val="VT0(15):26"/>
|
|
||||||
</v:userDefs>
|
|
||||||
<v:textBlock v:margins="rect(4,4,4,4)" v:tabSpace="42.5197"/>
|
|
||||||
<v:textRect cx="57.9325" cy="588.189" width="93.29" height="51.2036"/>
|
|
||||||
<path d="M7.68 588.19 L8.04 588.19 L107.83 588.19" class="st10"/>
|
|
||||||
<rect v:rectContext="textBkgnd" x="17.327" y="566.589" width="81.2109" height="43.1999" class="st12"/>
|
|
||||||
<text x="32.45" y="582.79" class="st13" v:langID="2052"><v:paragraph v:horizAlign="1"/><v:tabList/>->8004<v:newlineChar/><tspan
|
|
||||||
x="17.33" dy="1.2em" class="st6">Multi Conn</tspan></text> </g>
|
|
||||||
<g id="shape1005-149" v:mID="1005" v:groupContext="shape" v:layerMember="0" transform="translate(98.1493,-177.812)">
|
|
||||||
<title>动态连接线.1005</title>
|
|
||||||
<desc>->8005 Multi Conn</desc>
|
|
||||||
<v:userDefs>
|
|
||||||
<v:ud v:nameU="visVersion" v:prompt="" v:val="VT0(15):26"/>
|
|
||||||
</v:userDefs>
|
|
||||||
<v:textBlock v:margins="rect(4,4,4,4)" v:tabSpace="42.5197"/>
|
|
||||||
<v:textRect cx="60.0654" cy="527.376" width="93.29" height="51.2036"/>
|
|
||||||
<path d="M5.09 589.52 L5.33 589.25 L114.8 465.5" class="st10"/>
|
|
||||||
<rect v:rectContext="textBkgnd" x="19.4599" y="505.776" width="81.2109" height="43.1999" class="st12"/>
|
|
||||||
<text x="34.58" y="521.98" class="st13" v:langID="2052"><v:paragraph v:horizAlign="1"/><v:tabList/>->8005<v:newlineChar/><tspan
|
|
||||||
x="19.46" dy="1.2em" class="st6">Multi Conn</tspan></text> </g>
|
|
||||||
<g id="shape1006-159" v:mID="1006" v:groupContext="shape" v:layerMember="0" transform="translate(277.783,-354.331)">
|
|
||||||
<title>动态连接线.1006</title>
|
|
||||||
<desc>NPS & NPC Multiplexing Connection TCP or KCP Only One Conn Pe...</desc>
|
|
||||||
<v:userDefs>
|
|
||||||
<v:ud v:nameU="visVersion" v:prompt="" v:val="VT0(15):26"/>
|
|
||||||
</v:userDefs>
|
|
||||||
<v:textBlock v:margins="rect(4,4,4,4)" v:tabSpace="42.5197"/>
|
|
||||||
<v:textRect cx="70.4362" cy="602.362" width="103.62" height="159.204"/>
|
|
||||||
<path d="M7.68 602.36 L8.04 602.36 L132.83 602.36" class="st10"/>
|
|
||||||
<rect v:rectContext="textBkgnd" x="24.6671" y="526.762" width="91.5381" height="151.2" class="st12"/>
|
|
||||||
<text x="30.38" y="542.96" class="st13" v:langID="2052"><v:paragraph v:horizAlign="1"/><v:tabList/>NPS & NPC<v:newlineChar/><tspan
|
|
||||||
x="24.67" dy="1.2em" class="st6">Multiplexing<v:newlineChar/></tspan><tspan x="28.6" dy="1.2em" class="st6">Connection<v:newlineChar/></tspan><tspan
|
|
||||||
x="30.53" dy="1.2em" class="st6">TCP or KCP<v:newlineChar/></tspan><tspan x="36.41" dy="1.2em" class="st6">Only One<v:newlineChar/></tspan><tspan
|
|
||||||
x="32.66" dy="1.2em" class="st6">Conn Peer<v:newlineChar/></tspan><tspan x="55.18" dy="1.2em" class="st6">NPC</tspan></text> </g>
|
|
||||||
<g id="shape1007-174" v:mID="1007" v:groupContext="shape" v:layerMember="0" transform="translate(603.767,-380.876)">
|
|
||||||
<title>动态连接线.1007</title>
|
|
||||||
<desc>->PORT Multi Conn</desc>
|
|
||||||
<v:userDefs>
|
|
||||||
<v:ud v:nameU="visVersion" v:prompt="" v:val="VT0(15):26"/>
|
|
||||||
</v:userDefs>
|
|
||||||
<v:textBlock v:margins="rect(4,4,4,4)" v:tabSpace="42.5197"/>
|
|
||||||
<v:textRect cx="55.0044" cy="550.955" width="93.29" height="51.2036"/>
|
|
||||||
<path d="M5.09 589.52 L5.33 589.25 L105.29 476.25" class="st10"/>
|
|
||||||
<rect v:rectContext="textBkgnd" x="14.3989" y="529.355" width="81.2109" height="43.1999" class="st12"/>
|
|
||||||
<text x="27.89" y="545.56" class="st13" v:langID="2052"><v:paragraph v:horizAlign="1"/><v:tabList/>->PORT<v:newlineChar/><tspan
|
|
||||||
x="14.4" dy="1.2em" class="st6">Multi Conn</tspan></text> </g>
|
|
||||||
<g id="shape1008-184" v:mID="1008" v:groupContext="shape" v:layerMember="0" transform="translate(603.767,-340.157)">
|
|
||||||
<title>动态连接线.1008</title>
|
|
||||||
<desc>->PORT Multi Conn</desc>
|
|
||||||
<v:userDefs>
|
|
||||||
<v:ud v:nameU="visVersion" v:prompt="" v:val="VT0(15):26"/>
|
|
||||||
</v:userDefs>
|
|
||||||
<v:textBlock v:margins="rect(4,4,4,4)" v:tabSpace="42.5197"/>
|
|
||||||
<v:textRect cx="55.3104" cy="588.189" width="93.29" height="51.2036"/>
|
|
||||||
<path d="M7.68 588.19 L8.04 588.19 L102.58 588.19" class="st10"/>
|
|
||||||
<rect v:rectContext="textBkgnd" x="14.7049" y="566.589" width="81.2109" height="43.1999" class="st12"/>
|
|
||||||
<text x="28.19" y="582.79" class="st13" v:langID="2052"><v:paragraph v:horizAlign="1"/><v:tabList/>->PORT<v:newlineChar/><tspan
|
|
||||||
x="14.7" dy="1.2em" class="st6">Multi Conn</tspan></text> </g>
|
|
||||||
<g id="shape1009-194" v:mID="1009" v:groupContext="shape" v:layerMember="0" transform="translate(603.767,-313.612)">
|
|
||||||
<title>动态连接线.1009</title>
|
|
||||||
<desc>->PORT Multi Conn</desc>
|
|
||||||
<v:userDefs>
|
|
||||||
<v:ud v:nameU="visVersion" v:prompt="" v:val="VT0(15):26"/>
|
|
||||||
</v:userDefs>
|
|
||||||
<v:textBlock v:margins="rect(4,4,4,4)" v:tabSpace="42.5197"/>
|
|
||||||
<v:textRect cx="68.0438" cy="667.943" width="93.29" height="51.2036"/>
|
|
||||||
<path d="M5.09 601.03 L5.33 601.3 L105.29 714.3" class="st10"/>
|
|
||||||
<rect v:rectContext="textBkgnd" x="27.4383" y="646.343" width="81.2109" height="43.1999" class="st12"/>
|
|
||||||
<text x="40.93" y="662.54" class="st13" v:langID="2052"><v:paragraph v:horizAlign="1"/><v:tabList/>->PORT<v:newlineChar/><tspan
|
|
||||||
x="27.44" dy="1.2em" class="st6">Multi Conn</tspan></text> </g>
|
|
||||||
<g id="shape1010-204" v:mID="1010" v:groupContext="shape" v:layerMember="0" transform="translate(488.431,-340.157)">
|
|
||||||
<title>动态连接线.1010</title>
|
|
||||||
<desc>NPS & NPC</desc>
|
|
||||||
<v:userDefs>
|
|
||||||
<v:ud v:nameU="visVersion" v:prompt="" v:val="VT0(15):26"/>
|
|
||||||
</v:userDefs>
|
|
||||||
<v:textBlock v:margins="rect(4,4,4,4)" v:tabSpace="42.5197"/>
|
|
||||||
<v:textRect cx="27.9165" cy="588.189" width="90" height="72.8036"/>
|
|
||||||
<path d="M7.68 588.19 L8.04 588.19 L47.79 588.19" class="st10"/>
|
|
||||||
<rect v:rectContext="textBkgnd" x="12.6587" y="555.789" width="30.5156" height="64.7998" class="st12"/>
|
|
||||||
<text x="13.32" y="571.99" class="st13" v:langID="2052"><v:paragraph v:horizAlign="1"/><v:tabList/>NPS<v:newlineChar/><tspan
|
|
||||||
x="21.78" dy="1.2em" class="st6">&<v:newlineChar/></tspan><tspan x="12.66" dy="1.2em" class="st6">NPC</tspan></text> </g>
|
|
||||||
<g id="shape1011-215" v:mID="1011" v:groupContext="shape" transform="translate(34.0157,-62.8844)">
|
|
||||||
<title>工作表.1011</title>
|
|
||||||
<path d="M0 595.28 L398.27 595.28 L398.27 85.04 L0 85.04 L0 595.28 Z" class="st14"/>
|
|
||||||
</g>
|
|
||||||
<g id="shape1012-217" v:mID="1012" v:groupContext="shape" transform="translate(473.386,-62.8844)">
|
|
||||||
<title>工作表.1012</title>
|
|
||||||
<path d="M0 595.28 L320.31 595.28 L320.31 85.04 L0 85.04 L0 595.28 Z" class="st14"/>
|
|
||||||
</g>
|
|
||||||
<g id="shape1013-219" v:mID="1013" v:groupContext="shape" transform="translate(255.118,-496.063)">
|
|
||||||
<title>工作表.1013</title>
|
|
||||||
<desc>Internet</desc>
|
|
||||||
<v:textBlock v:margins="rect(4,4,4,4)" v:tabSpace="42.5197"/>
|
|
||||||
<v:textRect cx="63.7795" cy="559.843" width="127.56" height="70.8661"/>
|
|
||||||
<rect x="0" y="524.409" width="127.559" height="70.8661" class="st15"/>
|
|
||||||
<text x="23.98" y="567.04" class="st16" v:langID="2052"><v:paragraph v:horizAlign="1"/><v:tabList/>Internet</text> </g>
|
|
||||||
<g id="shape1014-222" v:mID="1014" v:groupContext="shape" transform="translate(517.323,-515.866)">
|
|
||||||
<title>工作表.1014</title>
|
|
||||||
<desc>Intranet</desc>
|
|
||||||
<v:textBlock v:margins="rect(4,4,4,4)" v:tabSpace="42.5197"/>
|
|
||||||
<v:textRect cx="76" cy="579.646" width="152.01" height="31.2598"/>
|
|
||||||
<rect x="0" y="564.016" width="152" height="31.2598" class="st15"/>
|
|
||||||
<text x="36.43" y="586.85" class="st16" v:langID="2052"><v:paragraph v:horizAlign="1"/><v:tabList/>Intranet</text> </g>
|
|
||||||
</g>
|
|
||||||
</svg>
|
|
Before Width: | Height: | Size: 58 KiB |
@ -36,3 +36,19 @@ WWW-Authenticate: Basic realm="easyProxy"
|
|||||||
|
|
||||||
`
|
`
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
MUX_PING_FLAG uint8 = iota
|
||||||
|
MUX_NEW_CONN_OK
|
||||||
|
MUX_NEW_CONN_Fail
|
||||||
|
MUX_NEW_MSG
|
||||||
|
MUX_NEW_MSG_PART
|
||||||
|
MUX_MSG_SEND_OK
|
||||||
|
MUX_NEW_CONN
|
||||||
|
MUX_CONN_CLOSE
|
||||||
|
MUX_PING_RETURN
|
||||||
|
MUX_PING int32 = -1
|
||||||
|
MAXIMUM_SEGMENT_SIZE = PoolSizeWindow
|
||||||
|
MAXIMUM_WINDOW_SIZE = 1 << 25 // 1<<31-1 TCP slide window size is very large,
|
||||||
|
// we use 32M, reduce memory usage
|
||||||
|
)
|
||||||
|
@ -1,48 +0,0 @@
|
|||||||
package common
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/astaxie/beego/logs"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
const MaxMsgLen = 5000
|
|
||||||
|
|
||||||
var logMsgs string
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
logs.Register("store", func() logs.Logger {
|
|
||||||
return new(StoreMsg)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetLogMsg() string {
|
|
||||||
return logMsgs
|
|
||||||
}
|
|
||||||
|
|
||||||
type StoreMsg struct {
|
|
||||||
}
|
|
||||||
|
|
||||||
func (lg *StoreMsg) Init(config string) error {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (lg *StoreMsg) WriteMsg(when time.Time, msg string, level int) error {
|
|
||||||
m := when.Format("2006-01-02 15:04:05") + " " + msg + "\r\n"
|
|
||||||
if len(logMsgs) > MaxMsgLen {
|
|
||||||
start := MaxMsgLen - len(m)
|
|
||||||
if start <= 0 {
|
|
||||||
start = MaxMsgLen
|
|
||||||
}
|
|
||||||
logMsgs = logMsgs[start:]
|
|
||||||
}
|
|
||||||
logMsgs += m
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (lg *StoreMsg) Destroy() {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (lg *StoreMsg) Flush() {
|
|
||||||
return
|
|
||||||
}
|
|
@ -3,11 +3,10 @@ package common
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"strings"
|
||||||
"net"
|
|
||||||
"strconv"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type NetPackager interface {
|
type NetPackager interface {
|
||||||
@ -15,205 +14,222 @@ type NetPackager interface {
|
|||||||
UnPack(reader io.Reader) (err error)
|
UnPack(reader io.Reader) (err error)
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
type BasePackager struct {
|
||||||
ipV4 = 1
|
Length uint16
|
||||||
domainName = 3
|
Content []byte
|
||||||
ipV6 = 4
|
|
||||||
)
|
|
||||||
|
|
||||||
type UDPHeader struct {
|
|
||||||
Rsv uint16
|
|
||||||
Frag uint8
|
|
||||||
Addr *Addr
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewUDPHeader(rsv uint16, frag uint8, addr *Addr) *UDPHeader {
|
func (Self *BasePackager) NewPac(contents ...interface{}) (err error) {
|
||||||
return &UDPHeader{
|
Self.clean()
|
||||||
Rsv: rsv,
|
for _, content := range contents {
|
||||||
Frag: frag,
|
switch content.(type) {
|
||||||
Addr: addr,
|
case nil:
|
||||||
}
|
Self.Content = Self.Content[:0]
|
||||||
}
|
case []byte:
|
||||||
|
err = Self.appendByte(content.([]byte))
|
||||||
type Addr struct {
|
case string:
|
||||||
Type uint8
|
err = Self.appendByte([]byte(content.(string)))
|
||||||
Host string
|
if err != nil {
|
||||||
Port uint16
|
return
|
||||||
}
|
}
|
||||||
|
err = Self.appendByte([]byte(CONN_DATA_SEQ))
|
||||||
func (addr *Addr) String() string {
|
default:
|
||||||
return net.JoinHostPort(addr.Host, strconv.Itoa(int(addr.Port)))
|
err = Self.marshal(content)
|
||||||
}
|
|
||||||
|
|
||||||
func (addr *Addr) Decode(b []byte) error {
|
|
||||||
addr.Type = b[0]
|
|
||||||
pos := 1
|
|
||||||
switch addr.Type {
|
|
||||||
case ipV4:
|
|
||||||
addr.Host = net.IP(b[pos : pos+net.IPv4len]).String()
|
|
||||||
pos += net.IPv4len
|
|
||||||
case ipV6:
|
|
||||||
addr.Host = net.IP(b[pos : pos+net.IPv6len]).String()
|
|
||||||
pos += net.IPv6len
|
|
||||||
case domainName:
|
|
||||||
addrlen := int(b[pos])
|
|
||||||
pos++
|
|
||||||
addr.Host = string(b[pos : pos+addrlen])
|
|
||||||
pos += addrlen
|
|
||||||
default:
|
|
||||||
return errors.New("decode error")
|
|
||||||
}
|
|
||||||
|
|
||||||
addr.Port = binary.BigEndian.Uint16(b[pos:])
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (addr *Addr) Encode(b []byte) (int, error) {
|
|
||||||
b[0] = addr.Type
|
|
||||||
pos := 1
|
|
||||||
switch addr.Type {
|
|
||||||
case ipV4:
|
|
||||||
ip4 := net.ParseIP(addr.Host).To4()
|
|
||||||
if ip4 == nil {
|
|
||||||
ip4 = net.IPv4zero.To4()
|
|
||||||
}
|
}
|
||||||
pos += copy(b[pos:], ip4)
|
|
||||||
case domainName:
|
|
||||||
b[pos] = byte(len(addr.Host))
|
|
||||||
pos++
|
|
||||||
pos += copy(b[pos:], []byte(addr.Host))
|
|
||||||
case ipV6:
|
|
||||||
ip16 := net.ParseIP(addr.Host).To16()
|
|
||||||
if ip16 == nil {
|
|
||||||
ip16 = net.IPv6zero.To16()
|
|
||||||
}
|
|
||||||
pos += copy(b[pos:], ip16)
|
|
||||||
default:
|
|
||||||
b[0] = ipV4
|
|
||||||
copy(b[pos:pos+4], net.IPv4zero.To4())
|
|
||||||
pos += 4
|
|
||||||
}
|
}
|
||||||
binary.BigEndian.PutUint16(b[pos:], addr.Port)
|
Self.setLength()
|
||||||
pos += 2
|
return
|
||||||
|
|
||||||
return pos, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *UDPHeader) Write(w io.Writer) error {
|
func (Self *BasePackager) appendByte(data []byte) (err error) {
|
||||||
b := BufPoolUdp.Get().([]byte)
|
m := len(Self.Content)
|
||||||
defer BufPoolUdp.Put(b)
|
n := m + len(data)
|
||||||
|
if n <= cap(Self.Content) {
|
||||||
binary.BigEndian.PutUint16(b[:2], h.Rsv)
|
Self.Content = Self.Content[0:n] // grow the length for copy
|
||||||
b[2] = h.Frag
|
copy(Self.Content[m:n], data)
|
||||||
|
return nil
|
||||||
addr := h.Addr
|
} else {
|
||||||
if addr == nil {
|
return errors.New("pack content too large")
|
||||||
addr = &Addr{}
|
|
||||||
}
|
}
|
||||||
length, _ := addr.Encode(b[3:])
|
|
||||||
|
|
||||||
_, err := w.Write(b[:3+length])
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type UDPDatagram struct {
|
//似乎这里涉及到父类作用域问题,当子类调用父类的方法时,其struct仅仅为父类的
|
||||||
Header *UDPHeader
|
func (Self *BasePackager) Pack(writer io.Writer) (err error) {
|
||||||
Data []byte
|
err = binary.Write(writer, binary.LittleEndian, Self.Length)
|
||||||
}
|
|
||||||
|
|
||||||
func ReadUDPDatagram(r io.Reader) (*UDPDatagram, error) {
|
|
||||||
b := BufPoolUdp.Get().([]byte)
|
|
||||||
defer BufPoolUdp.Put(b)
|
|
||||||
|
|
||||||
// when r is a streaming (such as TCP connection), we may read more than the required data,
|
|
||||||
// but we don't know how to handle it. So we use io.ReadFull to instead of io.ReadAtLeast
|
|
||||||
// to make sure that no redundant data will be discarded.
|
|
||||||
n, err := io.ReadFull(r, b[:5])
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return
|
||||||
}
|
}
|
||||||
|
err = binary.Write(writer, binary.LittleEndian, Self.Content)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
header := &UDPHeader{
|
//Unpack 会导致传入的数字类型转化成float64!!
|
||||||
Rsv: binary.BigEndian.Uint16(b[:2]),
|
//主要原因是json unmarshal并未传入正确的数据类型
|
||||||
Frag: b[2],
|
func (Self *BasePackager) UnPack(reader io.Reader) (n uint16, err error) {
|
||||||
|
Self.clean()
|
||||||
|
n += 2 // uint16
|
||||||
|
err = binary.Read(reader, binary.LittleEndian, &Self.Length)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
if int(Self.Length) > cap(Self.Content) {
|
||||||
|
err = errors.New("unpack err, content length too large")
|
||||||
|
}
|
||||||
|
Self.Content = Self.Content[:int(Self.Length)]
|
||||||
|
//n, err := io.ReadFull(reader, Self.Content)
|
||||||
|
//if n != int(Self.Length) {
|
||||||
|
// err = io.ErrUnexpectedEOF
|
||||||
|
//}
|
||||||
|
err = binary.Read(reader, binary.LittleEndian, Self.Content)
|
||||||
|
n += Self.Length
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
atype := b[3]
|
func (Self *BasePackager) marshal(content interface{}) (err error) {
|
||||||
hlen := 0
|
tmp, err := json.Marshal(content)
|
||||||
switch atype {
|
if err != nil {
|
||||||
case ipV4:
|
return err
|
||||||
hlen = 10
|
|
||||||
case ipV6:
|
|
||||||
hlen = 22
|
|
||||||
case domainName:
|
|
||||||
hlen = 7 + int(b[4])
|
|
||||||
default:
|
|
||||||
return nil, errors.New("addr not support")
|
|
||||||
}
|
}
|
||||||
dlen := int(header.Rsv)
|
err = Self.appendByte(tmp)
|
||||||
if dlen == 0 { // standard SOCKS5 UDP datagram
|
return
|
||||||
extra, err := ioutil.ReadAll(r) // we assume no redundant data
|
}
|
||||||
|
|
||||||
|
func (Self *BasePackager) Unmarshal(content interface{}) (err error) {
|
||||||
|
err = json.Unmarshal(Self.Content, content)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (Self *BasePackager) setLength() {
|
||||||
|
Self.Length = uint16(len(Self.Content))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (Self *BasePackager) clean() {
|
||||||
|
Self.Length = 0
|
||||||
|
Self.Content = Self.Content[:0] // reset length
|
||||||
|
}
|
||||||
|
|
||||||
|
func (Self *BasePackager) Split() (strList []string) {
|
||||||
|
n := bytes.IndexByte(Self.Content, 0)
|
||||||
|
strList = strings.Split(string(Self.Content[:n]), CONN_DATA_SEQ)
|
||||||
|
strList = strList[0 : len(strList)-1]
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
type ConnPackager struct { // Todo
|
||||||
|
ConnType uint8
|
||||||
|
BasePackager
|
||||||
|
}
|
||||||
|
|
||||||
|
func (Self *ConnPackager) NewPac(connType uint8, content ...interface{}) (err error) {
|
||||||
|
Self.ConnType = connType
|
||||||
|
err = Self.BasePackager.NewPac(content...)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (Self *ConnPackager) Pack(writer io.Writer) (err error) {
|
||||||
|
err = binary.Write(writer, binary.LittleEndian, Self.ConnType)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = Self.BasePackager.Pack(writer)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (Self *ConnPackager) UnPack(reader io.Reader) (n uint16, err error) {
|
||||||
|
err = binary.Read(reader, binary.LittleEndian, &Self.ConnType)
|
||||||
|
if err != nil && err != io.EOF {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
n, err = Self.BasePackager.UnPack(reader)
|
||||||
|
n += 2
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
type MuxPackager struct {
|
||||||
|
Flag uint8
|
||||||
|
Id int32
|
||||||
|
Window uint32
|
||||||
|
ReadLength uint32
|
||||||
|
BasePackager
|
||||||
|
}
|
||||||
|
|
||||||
|
func (Self *MuxPackager) NewPac(flag uint8, id int32, content ...interface{}) (err error) {
|
||||||
|
Self.Flag = flag
|
||||||
|
Self.Id = id
|
||||||
|
switch flag {
|
||||||
|
case MUX_PING_FLAG, MUX_PING_RETURN, MUX_NEW_MSG, MUX_NEW_MSG_PART:
|
||||||
|
Self.Content = WindowBuff.Get()
|
||||||
|
err = Self.BasePackager.NewPac(content...)
|
||||||
|
//logs.Warn(Self.Length, string(Self.Content))
|
||||||
|
case MUX_MSG_SEND_OK:
|
||||||
|
// MUX_MSG_SEND_OK contains two data
|
||||||
|
switch content[0].(type) {
|
||||||
|
case int:
|
||||||
|
Self.Window = uint32(content[0].(int))
|
||||||
|
case uint32:
|
||||||
|
Self.Window = content[0].(uint32)
|
||||||
|
}
|
||||||
|
switch content[1].(type) {
|
||||||
|
case int:
|
||||||
|
Self.ReadLength = uint32(content[1].(int))
|
||||||
|
case uint32:
|
||||||
|
Self.ReadLength = content[1].(uint32)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (Self *MuxPackager) Pack(writer io.Writer) (err error) {
|
||||||
|
err = binary.Write(writer, binary.LittleEndian, Self.Flag)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = binary.Write(writer, binary.LittleEndian, Self.Id)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
switch Self.Flag {
|
||||||
|
case MUX_NEW_MSG, MUX_NEW_MSG_PART, MUX_PING_FLAG, MUX_PING_RETURN:
|
||||||
|
err = Self.BasePackager.Pack(writer)
|
||||||
|
WindowBuff.Put(Self.Content)
|
||||||
|
case MUX_MSG_SEND_OK:
|
||||||
|
err = binary.Write(writer, binary.LittleEndian, Self.Window)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return
|
||||||
}
|
}
|
||||||
copy(b[n:], extra)
|
err = binary.Write(writer, binary.LittleEndian, Self.ReadLength)
|
||||||
n += len(extra) // total length
|
}
|
||||||
dlen = n - hlen // data length
|
return
|
||||||
} else { // extended feature, for UDP over TCP, using reserved field as data length
|
}
|
||||||
if _, err := io.ReadFull(r, b[n:hlen+dlen]); err != nil {
|
|
||||||
return nil, err
|
func (Self *MuxPackager) UnPack(reader io.Reader) (n uint16, err error) {
|
||||||
|
err = binary.Read(reader, binary.LittleEndian, &Self.Flag)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = binary.Read(reader, binary.LittleEndian, &Self.Id)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
switch Self.Flag {
|
||||||
|
case MUX_NEW_MSG, MUX_NEW_MSG_PART, MUX_PING_FLAG, MUX_PING_RETURN:
|
||||||
|
Self.Content = WindowBuff.Get() // need get a window buf from pool
|
||||||
|
Self.BasePackager.clean() // also clean the content
|
||||||
|
n, err = Self.BasePackager.UnPack(reader)
|
||||||
|
//logs.Warn("unpack", Self.Length, string(Self.Content))
|
||||||
|
case MUX_MSG_SEND_OK:
|
||||||
|
err = binary.Read(reader, binary.LittleEndian, &Self.Window)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
}
|
}
|
||||||
n = hlen + dlen
|
n += 4 // uint32
|
||||||
}
|
err = binary.Read(reader, binary.LittleEndian, &Self.ReadLength)
|
||||||
header.Addr = new(Addr)
|
n += 4 // uint32
|
||||||
if err := header.Addr.Decode(b[3:hlen]); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
data := make([]byte, dlen)
|
|
||||||
copy(data, b[hlen:n])
|
|
||||||
d := &UDPDatagram{
|
|
||||||
Header: header,
|
|
||||||
Data: data,
|
|
||||||
}
|
|
||||||
return d, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewUDPDatagram(header *UDPHeader, data []byte) *UDPDatagram {
|
|
||||||
return &UDPDatagram{
|
|
||||||
Header: header,
|
|
||||||
Data: data,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *UDPDatagram) Write(w io.Writer) error {
|
|
||||||
h := d.Header
|
|
||||||
if h == nil {
|
|
||||||
h = &UDPHeader{}
|
|
||||||
}
|
|
||||||
buf := bytes.Buffer{}
|
|
||||||
if err := h.Write(&buf); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if _, err := buf.Write(d.Data); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err := buf.WriteTo(w)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func ToSocksAddr(addr net.Addr) *Addr {
|
|
||||||
host := "0.0.0.0"
|
|
||||||
port := 0
|
|
||||||
if addr != nil {
|
|
||||||
h, p, _ := net.SplitHostPort(addr.String())
|
|
||||||
host = h
|
|
||||||
port, _ = strconv.Atoi(p)
|
|
||||||
}
|
|
||||||
return &Addr{
|
|
||||||
Type: ipV4,
|
|
||||||
Host: host,
|
|
||||||
Port: uint16(port),
|
|
||||||
}
|
}
|
||||||
|
n += 5 //uint8 int32
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,16 @@
|
|||||||
package common
|
package common
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"sync"
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
const PoolSize = 64 * 1024
|
const PoolSize = 64 * 1024
|
||||||
const PoolSizeSmall = 100
|
const PoolSizeSmall = 100
|
||||||
const PoolSizeUdp = 1472 + 200
|
const PoolSizeUdp = 1472
|
||||||
const PoolSizeCopy = 32 << 10
|
const PoolSizeCopy = 32 << 10
|
||||||
|
const PoolSizeBuffer = 4096
|
||||||
|
const PoolSizeWindow = PoolSizeBuffer - 2 - 4 - 4 - 1
|
||||||
|
|
||||||
var BufPool = sync.Pool{
|
var BufPool = sync.Pool{
|
||||||
New: func() interface{} {
|
New: func() interface{} {
|
||||||
@ -83,11 +86,112 @@ func (Self *copyBufferPool) Put(x []byte) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type windowBufferPool struct {
|
||||||
|
pool sync.Pool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (Self *windowBufferPool) New() {
|
||||||
|
Self.pool = sync.Pool{
|
||||||
|
New: func() interface{} {
|
||||||
|
return make([]byte, PoolSizeWindow, PoolSizeWindow)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (Self *windowBufferPool) Get() (buf []byte) {
|
||||||
|
buf = Self.pool.Get().([]byte)
|
||||||
|
return buf[:PoolSizeWindow]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (Self *windowBufferPool) Put(x []byte) {
|
||||||
|
Self.pool.Put(x[:PoolSizeWindow]) // make buf to full
|
||||||
|
}
|
||||||
|
|
||||||
|
type bufferPool struct {
|
||||||
|
pool sync.Pool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (Self *bufferPool) New() {
|
||||||
|
Self.pool = sync.Pool{
|
||||||
|
New: func() interface{} {
|
||||||
|
return bytes.NewBuffer(make([]byte, 0, PoolSizeBuffer))
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (Self *bufferPool) Get() *bytes.Buffer {
|
||||||
|
return Self.pool.Get().(*bytes.Buffer)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (Self *bufferPool) Put(x *bytes.Buffer) {
|
||||||
|
x.Reset()
|
||||||
|
Self.pool.Put(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
type muxPackagerPool struct {
|
||||||
|
pool sync.Pool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (Self *muxPackagerPool) New() {
|
||||||
|
Self.pool = sync.Pool{
|
||||||
|
New: func() interface{} {
|
||||||
|
pack := MuxPackager{}
|
||||||
|
return &pack
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (Self *muxPackagerPool) Get() *MuxPackager {
|
||||||
|
return Self.pool.Get().(*MuxPackager)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (Self *muxPackagerPool) Put(pack *MuxPackager) {
|
||||||
|
Self.pool.Put(pack)
|
||||||
|
}
|
||||||
|
|
||||||
|
type ListElement struct {
|
||||||
|
Buf []byte
|
||||||
|
L uint16
|
||||||
|
Part bool
|
||||||
|
}
|
||||||
|
|
||||||
|
type listElementPool struct {
|
||||||
|
pool sync.Pool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (Self *listElementPool) New() {
|
||||||
|
Self.pool = sync.Pool{
|
||||||
|
New: func() interface{} {
|
||||||
|
element := ListElement{}
|
||||||
|
return &element
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (Self *listElementPool) Get() *ListElement {
|
||||||
|
return Self.pool.Get().(*ListElement)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (Self *listElementPool) Put(element *ListElement) {
|
||||||
|
element.L = 0
|
||||||
|
element.Buf = nil
|
||||||
|
element.Part = false
|
||||||
|
Self.pool.Put(element)
|
||||||
|
}
|
||||||
|
|
||||||
var once = sync.Once{}
|
var once = sync.Once{}
|
||||||
|
var BuffPool = bufferPool{}
|
||||||
var CopyBuff = copyBufferPool{}
|
var CopyBuff = copyBufferPool{}
|
||||||
|
var MuxPack = muxPackagerPool{}
|
||||||
|
var WindowBuff = windowBufferPool{}
|
||||||
|
var ListElementPool = listElementPool{}
|
||||||
|
|
||||||
func newPool() {
|
func newPool() {
|
||||||
|
BuffPool.New()
|
||||||
CopyBuff.New()
|
CopyBuff.New()
|
||||||
|
MuxPack.New()
|
||||||
|
WindowBuff.New()
|
||||||
|
ListElementPool.New()
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
@ -1,29 +0,0 @@
|
|||||||
package common
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/astaxie/beego"
|
|
||||||
"github.com/astaxie/beego/logs"
|
|
||||||
"net/http"
|
|
||||||
_ "net/http/pprof"
|
|
||||||
)
|
|
||||||
|
|
||||||
func InitPProfFromFile() {
|
|
||||||
ip := beego.AppConfig.String("pprof_ip")
|
|
||||||
p := beego.AppConfig.String("pprof_port")
|
|
||||||
if len(ip) > 0 && len(p) > 0 && IsPort(p) {
|
|
||||||
runPProf(ip + ":" + p)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func InitPProfFromArg(arg string) {
|
|
||||||
if len(arg) > 0 {
|
|
||||||
runPProf(arg)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func runPProf(ipPort string) {
|
|
||||||
go func() {
|
|
||||||
_ = http.ListenAndServe(ipPort, nil)
|
|
||||||
}()
|
|
||||||
logs.Info("PProf debug listen on", ipPort)
|
|
||||||
}
|
|
@ -48,20 +48,9 @@ func IsWindows() bool {
|
|||||||
func GetLogPath() string {
|
func GetLogPath() string {
|
||||||
var path string
|
var path string
|
||||||
if IsWindows() {
|
if IsWindows() {
|
||||||
path = filepath.Join(GetAppPath(), "nps.log")
|
path = GetAppPath()
|
||||||
} else {
|
} else {
|
||||||
path = "/var/log/nps.log"
|
path = "/tmp"
|
||||||
}
|
|
||||||
return path
|
|
||||||
}
|
|
||||||
|
|
||||||
//interface npc log file path
|
|
||||||
func GetNpcLogPath() string {
|
|
||||||
var path string
|
|
||||||
if IsWindows() {
|
|
||||||
path = filepath.Join(GetAppPath(), "npc.log")
|
|
||||||
} else {
|
|
||||||
path = "/var/log/npc.log"
|
|
||||||
}
|
}
|
||||||
return path
|
return path
|
||||||
}
|
}
|
||||||
@ -76,14 +65,3 @@ func GetTmpPath() string {
|
|||||||
}
|
}
|
||||||
return path
|
return path
|
||||||
}
|
}
|
||||||
|
|
||||||
//config file path
|
|
||||||
func GetConfigPath() string {
|
|
||||||
var path string
|
|
||||||
if IsWindows() {
|
|
||||||
path = filepath.Join(GetAppPath(), "conf/npc.conf")
|
|
||||||
} else {
|
|
||||||
path = "conf/npc.conf"
|
|
||||||
}
|
|
||||||
return path
|
|
||||||
}
|
|
||||||
|
@ -2,11 +2,8 @@ package common
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"ehang.io/nps/lib/version"
|
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"html/template"
|
"html/template"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
@ -18,7 +15,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"ehang.io/nps/lib/crypt"
|
"github.com/cnlh/nps/lib/crypt"
|
||||||
)
|
)
|
||||||
|
|
||||||
//Get the corresponding IP address through domain name
|
//Get the corresponding IP address through domain name
|
||||||
@ -53,10 +50,7 @@ func DomainCheck(domain string) bool {
|
|||||||
func CheckAuth(r *http.Request, user, passwd string) bool {
|
func CheckAuth(r *http.Request, user, passwd string) bool {
|
||||||
s := strings.SplitN(r.Header.Get("Authorization"), " ", 2)
|
s := strings.SplitN(r.Header.Get("Authorization"), " ", 2)
|
||||||
if len(s) != 2 {
|
if len(s) != 2 {
|
||||||
s = strings.SplitN(r.Header.Get("Proxy-Authorization"), " ", 2)
|
return false
|
||||||
if len(s) != 2 {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
b, err := base64.StdEncoding.DecodeString(s[1])
|
b, err := base64.StdEncoding.DecodeString(s[1])
|
||||||
@ -100,7 +94,7 @@ func Getverifyval(vkey string) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//Change headers and host of request
|
//Change headers and host of request
|
||||||
func ChangeHostAndHeader(r *http.Request, host string, header string, addr string, addOrigin bool) {
|
func ChangeHostAndHeader(r *http.Request, host string, header string, addr string) {
|
||||||
if host != "" {
|
if host != "" {
|
||||||
r.Host = host
|
r.Host = host
|
||||||
}
|
}
|
||||||
@ -115,12 +109,10 @@ func ChangeHostAndHeader(r *http.Request, host string, header string, addr strin
|
|||||||
}
|
}
|
||||||
addr = strings.Split(addr, ":")[0]
|
addr = strings.Split(addr, ":")[0]
|
||||||
if prior, ok := r.Header["X-Forwarded-For"]; ok {
|
if prior, ok := r.Header["X-Forwarded-For"]; ok {
|
||||||
addr = strings.Join(prior, ", ") + ", " + addr
|
addr = strings.Join(prior, ", ") + ", " + addr
|
||||||
}
|
}
|
||||||
if addOrigin {
|
r.Header.Set("X-Forwarded-For", addr)
|
||||||
r.Header.Set("X-Forwarded-For", addr)
|
r.Header.Set("X-Real-IP", addr)
|
||||||
r.Header.Set("X-Real-IP", addr)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//Read file content by file path
|
//Read file content by file path
|
||||||
@ -129,7 +121,6 @@ func ReadAllFromFile(filePath string) ([]byte, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
defer f.Close()
|
|
||||||
return ioutil.ReadAll(f)
|
return ioutil.ReadAll(f)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -404,66 +395,3 @@ func GetExtFromPath(path string) string {
|
|||||||
}
|
}
|
||||||
return string(re.Find([]byte(s[0])))
|
return string(re.Find([]byte(s[0])))
|
||||||
}
|
}
|
||||||
|
|
||||||
var externalIp string
|
|
||||||
|
|
||||||
func GetExternalIp() string {
|
|
||||||
if externalIp != "" {
|
|
||||||
return externalIp
|
|
||||||
}
|
|
||||||
resp, err := http.Get("http://myexternalip.com/raw")
|
|
||||||
if err != nil {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
defer resp.Body.Close()
|
|
||||||
content, _ := ioutil.ReadAll(resp.Body)
|
|
||||||
externalIp = string(content)
|
|
||||||
return externalIp
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetIntranetIp() (error, string) {
|
|
||||||
addrs, err := net.InterfaceAddrs()
|
|
||||||
if err != nil {
|
|
||||||
return nil, ""
|
|
||||||
}
|
|
||||||
for _, address := range addrs {
|
|
||||||
// 检查ip地址判断是否回环地址
|
|
||||||
if ipnet, ok := address.(*net.IPNet); ok && !ipnet.IP.IsLoopback() {
|
|
||||||
if ipnet.IP.To4() != nil {
|
|
||||||
return nil, ipnet.IP.To4().String()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return errors.New("get intranet ip error"), ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func IsPublicIP(IP net.IP) bool {
|
|
||||||
if IP.IsLoopback() || IP.IsLinkLocalMulticast() || IP.IsLinkLocalUnicast() {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if ip4 := IP.To4(); ip4 != nil {
|
|
||||||
switch true {
|
|
||||||
case ip4[0] == 10:
|
|
||||||
return false
|
|
||||||
case ip4[0] == 172 && ip4[1] >= 16 && ip4[1] <= 31:
|
|
||||||
return false
|
|
||||||
case ip4[0] == 192 && ip4[1] == 168:
|
|
||||||
return false
|
|
||||||
default:
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetServerIpByClientIp(clientIp net.IP) string {
|
|
||||||
if IsPublicIP(clientIp) {
|
|
||||||
return GetExternalIp()
|
|
||||||
}
|
|
||||||
_, ip := GetIntranetIp()
|
|
||||||
return ip
|
|
||||||
}
|
|
||||||
|
|
||||||
func PrintVersion() {
|
|
||||||
fmt.Printf("Version: %s\nCore version: %s\nSame core version of client and server can connect each other\n", version.VERSION, version.GetVersion())
|
|
||||||
}
|
|
||||||
|
@ -6,8 +6,8 @@ import (
|
|||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"ehang.io/nps/lib/common"
|
"github.com/cnlh/nps/lib/common"
|
||||||
"ehang.io/nps/lib/file"
|
"github.com/cnlh/nps/lib/file"
|
||||||
)
|
)
|
||||||
|
|
||||||
type CommonConfig struct {
|
type CommonConfig struct {
|
||||||
@ -17,7 +17,6 @@ type CommonConfig struct {
|
|||||||
AutoReconnection bool
|
AutoReconnection bool
|
||||||
ProxyUrl string
|
ProxyUrl string
|
||||||
Client *file.Client
|
Client *file.Client
|
||||||
DisconnectTime int
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type LocalServer struct {
|
type LocalServer struct {
|
||||||
@ -146,10 +145,6 @@ func dealCommon(s string) *CommonConfig {
|
|||||||
c.Client.MaxConn = common.GetIntNoErrByStr(item[1])
|
c.Client.MaxConn = common.GetIntNoErrByStr(item[1])
|
||||||
case "remark":
|
case "remark":
|
||||||
c.Client.Remark = item[1]
|
c.Client.Remark = item[1]
|
||||||
case "pprof_addr":
|
|
||||||
common.InitPProfFromArg(item[1])
|
|
||||||
case "disconnect_timeout":
|
|
||||||
c.DisconnectTime = common.GetIntNoErrByStr(item[1])
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return c
|
return c
|
||||||
@ -246,15 +241,13 @@ func dealTunnel(s string) *file.Tunnel {
|
|||||||
t.StripPre = item[1]
|
t.StripPre = item[1]
|
||||||
case "multi_account":
|
case "multi_account":
|
||||||
t.MultiAccount = &file.MultiAccount{}
|
t.MultiAccount = &file.MultiAccount{}
|
||||||
if common.FileExists(item[1]) {
|
if b, err := common.ReadAllFromFile(item[1]); err != nil {
|
||||||
if b, err := common.ReadAllFromFile(item[1]); err != nil {
|
panic(err)
|
||||||
|
} else {
|
||||||
|
if content, err := common.ParseStr(string(b)); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
} else {
|
} else {
|
||||||
if content, err := common.ParseStr(string(b)); err != nil {
|
t.MultiAccount.AccountMap = dealMultiUser(content)
|
||||||
panic(err)
|
|
||||||
} else {
|
|
||||||
t.MultiAccount.AccountMap = dealMultiUser(content)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -302,7 +295,7 @@ func delLocalService(s string) *LocalServer {
|
|||||||
|
|
||||||
func getAllTitle(content string) (arr []string, err error) {
|
func getAllTitle(content string) (arr []string, err error) {
|
||||||
var re *regexp.Regexp
|
var re *regexp.Regexp
|
||||||
re, err = regexp.Compile(`(?m)^\[[^\[\]\r\n]+\]`)
|
re, err = regexp.Compile(`\[.+?\]`)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -3,25 +3,24 @@ package conn
|
|||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
"bytes"
|
"bytes"
|
||||||
"ehang.io/nps/lib/goroutine"
|
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"github.com/astaxie/beego/logs"
|
"github.com/astaxie/beego/logs"
|
||||||
|
"github.com/cnlh/nps/lib/goroutine"
|
||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"ehang.io/nps/lib/common"
|
"github.com/cnlh/nps/lib/common"
|
||||||
"ehang.io/nps/lib/crypt"
|
"github.com/cnlh/nps/lib/crypt"
|
||||||
"ehang.io/nps/lib/file"
|
"github.com/cnlh/nps/lib/file"
|
||||||
"ehang.io/nps/lib/pmux"
|
"github.com/cnlh/nps/lib/mux"
|
||||||
"ehang.io/nps/lib/rate"
|
"github.com/cnlh/nps/lib/rate"
|
||||||
"github.com/xtaci/kcp-go"
|
"github.com/xtaci/kcp-go"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -35,33 +34,11 @@ func NewConn(conn net.Conn) *Conn {
|
|||||||
return &Conn{Conn: conn}
|
return &Conn{Conn: conn}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Conn) readRequest(buf []byte) (n int, err error) {
|
|
||||||
var rd int
|
|
||||||
for {
|
|
||||||
rd, err = s.Read(buf[n:])
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
n += rd
|
|
||||||
if n < 4 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if string(buf[n-4:n]) == "\r\n\r\n" {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// buf is full, can't contain the request
|
|
||||||
if n == cap(buf) {
|
|
||||||
err = io.ErrUnexpectedEOF
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//get host 、connection type、method...from connection
|
//get host 、connection type、method...from connection
|
||||||
func (s *Conn) GetHost() (method, address string, rb []byte, err error, r *http.Request) {
|
func (s *Conn) GetHost() (method, address string, rb []byte, err error, r *http.Request) {
|
||||||
var b [32 * 1024]byte
|
var b [32 * 1024]byte
|
||||||
var n int
|
var n int
|
||||||
if n, err = s.readRequest(b[:]); err != nil {
|
if n, err = s.Read(b[:]); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
rb = b[:n]
|
rb = b[:n]
|
||||||
@ -110,7 +87,7 @@ func (s *Conn) GetShortContent(l int) (b []byte, err error) {
|
|||||||
|
|
||||||
//读取指定长度内容
|
//读取指定长度内容
|
||||||
func (s *Conn) ReadLen(cLen int, buf []byte) (int, error) {
|
func (s *Conn) ReadLen(cLen int, buf []byte) (int, error) {
|
||||||
if cLen > len(buf) || cLen <= 0 {
|
if cLen > len(buf) {
|
||||||
return 0, errors.New("长度错误" + strconv.Itoa(cLen))
|
return 0, errors.New("长度错误" + strconv.Itoa(cLen))
|
||||||
}
|
}
|
||||||
if n, err := io.ReadFull(s, buf[:cLen]); err != nil || n != cLen {
|
if n, err := io.ReadFull(s, buf[:cLen]); err != nil || n != cLen {
|
||||||
@ -147,10 +124,10 @@ func (s *Conn) SetAlive(tp string) {
|
|||||||
case *net.TCPConn:
|
case *net.TCPConn:
|
||||||
conn := s.Conn.(*net.TCPConn)
|
conn := s.Conn.(*net.TCPConn)
|
||||||
conn.SetReadDeadline(time.Time{})
|
conn.SetReadDeadline(time.Time{})
|
||||||
//conn.SetKeepAlive(false)
|
conn.SetKeepAlive(true)
|
||||||
//conn.SetKeepAlivePeriod(time.Duration(2 * time.Second))
|
conn.SetKeepAlivePeriod(time.Duration(2 * time.Second))
|
||||||
case *pmux.PortConn:
|
case *mux.PortConn:
|
||||||
s.Conn.(*pmux.PortConn).SetReadDeadline(time.Time{})
|
s.Conn.(*mux.PortConn).SetReadDeadline(time.Time{})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -161,8 +138,8 @@ func (s *Conn) SetReadDeadlineBySecond(t time.Duration) {
|
|||||||
s.Conn.(*kcp.UDPSession).SetReadDeadline(time.Now().Add(time.Duration(t) * time.Second))
|
s.Conn.(*kcp.UDPSession).SetReadDeadline(time.Now().Add(time.Duration(t) * time.Second))
|
||||||
case *net.TCPConn:
|
case *net.TCPConn:
|
||||||
s.Conn.(*net.TCPConn).SetReadDeadline(time.Now().Add(time.Duration(t) * time.Second))
|
s.Conn.(*net.TCPConn).SetReadDeadline(time.Now().Add(time.Duration(t) * time.Second))
|
||||||
case *pmux.PortConn:
|
case *mux.PortConn:
|
||||||
s.Conn.(*pmux.PortConn).SetReadDeadline(time.Now().Add(time.Duration(t) * time.Second))
|
s.Conn.(*mux.PortConn).SetReadDeadline(time.Now().Add(time.Duration(t) * time.Second))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -394,10 +371,7 @@ func CopyWaitGroup(conn1, conn2 net.Conn, crypt bool, snappy bool, rate *rate.Ra
|
|||||||
//if flow != nil {
|
//if flow != nil {
|
||||||
// flow.Add(in, out)
|
// flow.Add(in, out)
|
||||||
//}
|
//}
|
||||||
wg := new(sync.WaitGroup)
|
err := goroutine.CopyConnsPool.Invoke(goroutine.NewConns(connHandle, conn2, flow))
|
||||||
wg.Add(1)
|
|
||||||
err := goroutine.CopyConnsPool.Invoke(goroutine.NewConns(connHandle, conn2, flow, wg))
|
|
||||||
wg.Wait()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logs.Error(err)
|
logs.Error(err)
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
package conn
|
package conn
|
||||||
|
|
||||||
import "time"
|
|
||||||
|
|
||||||
type Secret struct {
|
type Secret struct {
|
||||||
Password string
|
Password string
|
||||||
Conn *Conn
|
Conn *Conn
|
||||||
@ -21,20 +19,9 @@ type Link struct {
|
|||||||
Compress bool
|
Compress bool
|
||||||
LocalProxy bool
|
LocalProxy bool
|
||||||
RemoteAddr string
|
RemoteAddr string
|
||||||
Option Options
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type Option func(*Options)
|
func NewLink(connType string, host string, crypt bool, compress bool, remoteAddr string, localProxy bool) *Link {
|
||||||
|
|
||||||
type Options struct {
|
|
||||||
Timeout time.Duration
|
|
||||||
}
|
|
||||||
|
|
||||||
var defaultTimeOut = time.Second * 5
|
|
||||||
|
|
||||||
func NewLink(connType string, host string, crypt bool, compress bool, remoteAddr string, localProxy bool, opts ...Option) *Link {
|
|
||||||
options := newOptions(opts...)
|
|
||||||
|
|
||||||
return &Link{
|
return &Link{
|
||||||
RemoteAddr: remoteAddr,
|
RemoteAddr: remoteAddr,
|
||||||
ConnType: connType,
|
ConnType: connType,
|
||||||
@ -42,22 +29,5 @@ func NewLink(connType string, host string, crypt bool, compress bool, remoteAddr
|
|||||||
Crypt: crypt,
|
Crypt: crypt,
|
||||||
Compress: compress,
|
Compress: compress,
|
||||||
LocalProxy: localProxy,
|
LocalProxy: localProxy,
|
||||||
Option: options,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func newOptions(opts ...Option) Options {
|
|
||||||
opt := Options{
|
|
||||||
Timeout: defaultTimeOut,
|
|
||||||
}
|
|
||||||
for _, o := range opts {
|
|
||||||
o(&opt)
|
|
||||||
}
|
|
||||||
return opt
|
|
||||||
}
|
|
||||||
|
|
||||||
func LinkTimeout(t time.Duration) Option {
|
|
||||||
return func(opt *Options) {
|
|
||||||
opt.Timeout = t
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,23 +1,21 @@
|
|||||||
package conn
|
package conn
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"io"
|
"io"
|
||||||
|
|
||||||
|
"github.com/cnlh/nps/lib/common"
|
||||||
"github.com/golang/snappy"
|
"github.com/golang/snappy"
|
||||||
)
|
)
|
||||||
|
|
||||||
type SnappyConn struct {
|
type SnappyConn struct {
|
||||||
w *snappy.Writer
|
w *snappy.Writer
|
||||||
r *snappy.Reader
|
r *snappy.Reader
|
||||||
c io.Closer
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewSnappyConn(conn io.ReadWriteCloser) *SnappyConn {
|
func NewSnappyConn(conn io.ReadWriteCloser) *SnappyConn {
|
||||||
c := new(SnappyConn)
|
c := new(SnappyConn)
|
||||||
c.w = snappy.NewBufferedWriter(conn)
|
c.w = snappy.NewBufferedWriter(conn)
|
||||||
c.r = snappy.NewReader(conn)
|
c.r = snappy.NewReader(conn)
|
||||||
c.c = conn.(io.Closer)
|
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -34,20 +32,16 @@ func (s *SnappyConn) Write(b []byte) (n int, err error) {
|
|||||||
|
|
||||||
//snappy压缩读
|
//snappy压缩读
|
||||||
func (s *SnappyConn) Read(b []byte) (n int, err error) {
|
func (s *SnappyConn) Read(b []byte) (n int, err error) {
|
||||||
return s.r.Read(b)
|
buf := common.BufPool.Get().([]byte)
|
||||||
|
defer common.BufPool.Put(buf)
|
||||||
|
if n, err = s.r.Read(buf); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
copy(b, buf[:n])
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *SnappyConn) Close() error {
|
func (s *SnappyConn) Close() error {
|
||||||
err := s.w.Close()
|
s.w.Close()
|
||||||
err2 := s.c.Close()
|
return s.w.Close()
|
||||||
if err != nil && err2 == nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err == nil && err2 != nil {
|
|
||||||
return err2
|
|
||||||
}
|
|
||||||
if err != nil && err2 != nil {
|
|
||||||
return errors.New(err.Error() + err2.Error())
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
@ -1,37 +1,22 @@
|
|||||||
package crypt
|
package crypt
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/rand"
|
|
||||||
"crypto/rsa"
|
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"crypto/x509"
|
|
||||||
"crypto/x509/pkix"
|
|
||||||
"encoding/pem"
|
|
||||||
"log"
|
|
||||||
"math/big"
|
|
||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/astaxie/beego/logs"
|
"github.com/astaxie/beego/logs"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var pemPath, keyPath string
|
||||||
cert tls.Certificate
|
|
||||||
)
|
|
||||||
|
|
||||||
func InitTls() {
|
func InitTls(pem, key string) {
|
||||||
c, k, err := generateKeyPair("NPS Org")
|
pemPath = pem
|
||||||
if err == nil {
|
keyPath = key
|
||||||
cert, err = tls.X509KeyPair(c, k)
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalln("Error initializing crypto certs", err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewTlsServerConn(conn net.Conn) net.Conn {
|
func NewTlsServerConn(conn net.Conn) net.Conn {
|
||||||
var err error
|
cert, err := tls.LoadX509KeyPair(pemPath, keyPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logs.Error(err)
|
logs.Error(err)
|
||||||
os.Exit(0)
|
os.Exit(0)
|
||||||
@ -47,41 +32,3 @@ func NewTlsClientConn(conn net.Conn) net.Conn {
|
|||||||
}
|
}
|
||||||
return tls.Client(conn, conf)
|
return tls.Client(conn, conf)
|
||||||
}
|
}
|
||||||
|
|
||||||
func generateKeyPair(CommonName string) (rawCert, rawKey []byte, err error) {
|
|
||||||
// Create private key and self-signed certificate
|
|
||||||
// Adapted from https://golang.org/src/crypto/tls/generate_cert.go
|
|
||||||
|
|
||||||
priv, err := rsa.GenerateKey(rand.Reader, 2048)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
validFor := time.Hour * 24 * 365 * 10 // ten years
|
|
||||||
notBefore := time.Now()
|
|
||||||
notAfter := notBefore.Add(validFor)
|
|
||||||
serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
|
|
||||||
serialNumber, err := rand.Int(rand.Reader, serialNumberLimit)
|
|
||||||
template := x509.Certificate{
|
|
||||||
SerialNumber: serialNumber,
|
|
||||||
Subject: pkix.Name{
|
|
||||||
Organization: []string{"My Company Name LTD."},
|
|
||||||
CommonName: CommonName,
|
|
||||||
Country: []string{"US"},
|
|
||||||
},
|
|
||||||
NotBefore: notBefore,
|
|
||||||
NotAfter: notAfter,
|
|
||||||
|
|
||||||
KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
|
|
||||||
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
|
|
||||||
BasicConstraintsValid: true,
|
|
||||||
}
|
|
||||||
derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, &priv.PublicKey, priv)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
rawCert = pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: derBytes})
|
|
||||||
rawKey = pem.EncodeToMemory(&pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(priv)})
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
@ -9,7 +9,7 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"ehang.io/nps/lib/common"
|
"github.com/cnlh/nps/lib/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
func InitDaemon(f string, runPath string, pidPath string) {
|
func InitDaemon(f string, runPath string, pidPath string) {
|
||||||
|
@ -8,8 +8,8 @@ import (
|
|||||||
"path/filepath"
|
"path/filepath"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
"ehang.io/nps/lib/common"
|
|
||||||
"github.com/astaxie/beego"
|
"github.com/astaxie/beego"
|
||||||
|
"github.com/cnlh/nps/lib/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
@ -4,13 +4,14 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"regexp"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"ehang.io/nps/lib/common"
|
"github.com/cnlh/nps/lib/common"
|
||||||
"ehang.io/nps/lib/crypt"
|
"github.com/cnlh/nps/lib/crypt"
|
||||||
"ehang.io/nps/lib/rate"
|
"github.com/cnlh/nps/lib/rate"
|
||||||
)
|
)
|
||||||
|
|
||||||
type DbUtils struct {
|
type DbUtils struct {
|
||||||
@ -327,16 +328,13 @@ func (s *DbUtils) GetInfoByHost(host string, r *http.Request) (h *Host, err erro
|
|||||||
}
|
}
|
||||||
//Remove http(s) http(s)://a.proxy.com
|
//Remove http(s) http(s)://a.proxy.com
|
||||||
//*.proxy.com *.a.proxy.com Do some pan-parsing
|
//*.proxy.com *.a.proxy.com Do some pan-parsing
|
||||||
if v.Scheme != "all" && v.Scheme != r.URL.Scheme {
|
tmp := strings.Replace(v.Host, "*", `\w+?`, -1)
|
||||||
|
var re *regexp.Regexp
|
||||||
|
if re, err = regexp.Compile(tmp); err != nil {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
tmpHost := v.Host
|
if len(re.FindAllString(host, -1)) > 0 && (v.Scheme == "all" || v.Scheme == r.URL.Scheme) {
|
||||||
if strings.Contains(tmpHost, "*") {
|
//URL routing
|
||||||
tmpHost = strings.Replace(tmpHost, "*", "", -1)
|
|
||||||
if strings.Contains(host, tmpHost) {
|
|
||||||
hosts = append(hosts, v)
|
|
||||||
}
|
|
||||||
} else if v.Host == host {
|
|
||||||
hosts = append(hosts, v)
|
hosts = append(hosts, v)
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
|
@ -3,15 +3,14 @@ package file
|
|||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"github.com/astaxie/beego/logs"
|
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
|
|
||||||
"ehang.io/nps/lib/common"
|
"github.com/cnlh/nps/lib/common"
|
||||||
"ehang.io/nps/lib/rate"
|
"github.com/cnlh/nps/lib/rate"
|
||||||
)
|
)
|
||||||
|
|
||||||
func NewJsonDb(runPath string) *JsonDb {
|
func NewJsonDb(runPath string) *JsonDb {
|
||||||
@ -100,28 +99,16 @@ func (s *JsonDb) GetClient(id int) (c *Client, err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var hostLock sync.Mutex
|
|
||||||
|
|
||||||
func (s *JsonDb) StoreHostToJsonFile() {
|
func (s *JsonDb) StoreHostToJsonFile() {
|
||||||
hostLock.Lock()
|
|
||||||
storeSyncMapToFile(s.Hosts, s.HostFilePath)
|
storeSyncMapToFile(s.Hosts, s.HostFilePath)
|
||||||
hostLock.Unlock()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var taskLock sync.Mutex
|
|
||||||
|
|
||||||
func (s *JsonDb) StoreTasksToJsonFile() {
|
func (s *JsonDb) StoreTasksToJsonFile() {
|
||||||
taskLock.Lock()
|
|
||||||
storeSyncMapToFile(s.Tasks, s.TaskFilePath)
|
storeSyncMapToFile(s.Tasks, s.TaskFilePath)
|
||||||
taskLock.Unlock()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var clientLock sync.Mutex
|
|
||||||
|
|
||||||
func (s *JsonDb) StoreClientsToJsonFile() {
|
func (s *JsonDb) StoreClientsToJsonFile() {
|
||||||
clientLock.Lock()
|
|
||||||
storeSyncMapToFile(s.Clients, s.ClientFilePath)
|
storeSyncMapToFile(s.Clients, s.ClientFilePath)
|
||||||
clientLock.Unlock()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *JsonDb) GetClientId() int32 {
|
func (s *JsonDb) GetClientId() int32 {
|
||||||
@ -147,11 +134,11 @@ func loadSyncMapFromFile(filePath string, f func(value string)) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func storeSyncMapToFile(m sync.Map, filePath string) {
|
func storeSyncMapToFile(m sync.Map, filePath string) {
|
||||||
file, err := os.Create(filePath + ".tmp")
|
file, err := os.Create(filePath)
|
||||||
// first create a temporary file to store
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
defer file.Close()
|
||||||
m.Range(func(key, value interface{}) bool {
|
m.Range(func(key, value interface{}) bool {
|
||||||
var b []byte
|
var b []byte
|
||||||
var err error
|
var err error
|
||||||
@ -190,12 +177,4 @@ func storeSyncMapToFile(m sync.Map, filePath string) {
|
|||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
})
|
})
|
||||||
_ = file.Sync()
|
|
||||||
_ = file.Close()
|
|
||||||
// must close file first, then rename it
|
|
||||||
err = os.Rename(filePath+".tmp", filePath)
|
|
||||||
if err != nil {
|
|
||||||
logs.Error(err, "store to file err, data will lost")
|
|
||||||
}
|
|
||||||
// replace the file, maybe provides atomic operation
|
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@ import (
|
|||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"ehang.io/nps/lib/rate"
|
"github.com/cnlh/nps/lib/rate"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -50,7 +50,6 @@ type Client struct {
|
|||||||
WebPassword string //the password of web login
|
WebPassword string //the password of web login
|
||||||
ConfigConnAllow bool //is allow connected by config file
|
ConfigConnAllow bool //is allow connected by config file
|
||||||
MaxTunnelNum int
|
MaxTunnelNum int
|
||||||
Version string
|
|
||||||
sync.RWMutex
|
sync.RWMutex
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
package goroutine
|
package goroutine
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"ehang.io/nps/lib/common"
|
"github.com/cnlh/nps/lib/common"
|
||||||
"ehang.io/nps/lib/file"
|
"github.com/cnlh/nps/lib/file"
|
||||||
"github.com/panjf2000/ants/v2"
|
"github.com/panjf2000/ants/v2"
|
||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
@ -44,15 +44,13 @@ type Conns struct {
|
|||||||
conn1 io.ReadWriteCloser // mux connection
|
conn1 io.ReadWriteCloser // mux connection
|
||||||
conn2 net.Conn // outside connection
|
conn2 net.Conn // outside connection
|
||||||
flow *file.Flow
|
flow *file.Flow
|
||||||
wg *sync.WaitGroup
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewConns(c1 io.ReadWriteCloser, c2 net.Conn, flow *file.Flow, wg *sync.WaitGroup) Conns {
|
func NewConns(c1 io.ReadWriteCloser, c2 net.Conn, flow *file.Flow) Conns {
|
||||||
return Conns{
|
return Conns{
|
||||||
conn1: c1,
|
conn1: c1,
|
||||||
conn2: c2,
|
conn2: c2,
|
||||||
flow: flow,
|
flow: flow,
|
||||||
wg: wg,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -69,7 +67,6 @@ func copyConns(group interface{}) {
|
|||||||
if conns.flow != nil {
|
if conns.flow != nil {
|
||||||
conns.flow.Add(in, out)
|
conns.flow.Add(in, out)
|
||||||
}
|
}
|
||||||
conns.wg.Done()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var connCopyPool, _ = ants.NewPoolWithFunc(200000, copyConnGroup, ants.WithNonblocking(false))
|
var connCopyPool, _ = ants.NewPoolWithFunc(200000, copyConnGroup, ants.WithNonblocking(false))
|
||||||
|
@ -1,269 +1,88 @@
|
|||||||
package install
|
package install
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"ehang.io/nps/lib/common"
|
|
||||||
"encoding/json"
|
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/c4milo/unpackit"
|
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/cnlh/nps/lib/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Keep it in sync with the template from service_sysv_linux.go file
|
func InstallNps() {
|
||||||
// Use "ps | grep -v grep | grep $(get_pid)" because "ps PID" may not work on OpenWrt
|
unit := `[Unit]
|
||||||
const SysvScript = `#!/bin/sh
|
Description=nps - convenient proxy server
|
||||||
# For RedHat and cousins:
|
Documentation=https://github.com/cnlh/nps/
|
||||||
# chkconfig: - 99 01
|
After=network-online.target remote-fs.target nss-lookup.target
|
||||||
# description: {{.Description}}
|
Wants=network-online.target`
|
||||||
# processname: {{.Path}}
|
service := `[Service]
|
||||||
### BEGIN INIT INFO
|
Type=simple
|
||||||
# Provides: {{.Path}}
|
KillMode=process
|
||||||
# Required-Start:
|
|
||||||
# Required-Stop:
|
|
||||||
# Default-Start: 2 3 4 5
|
|
||||||
# Default-Stop: 0 1 6
|
|
||||||
# Short-Description: {{.DisplayName}}
|
|
||||||
# Description: {{.Description}}
|
|
||||||
### END INIT INFO
|
|
||||||
cmd="{{.Path}}{{range .Arguments}} {{.|cmd}}{{end}}"
|
|
||||||
name=$(basename $(readlink -f $0))
|
|
||||||
pid_file="/var/run/$name.pid"
|
|
||||||
stdout_log="/var/log/$name.log"
|
|
||||||
stderr_log="/var/log/$name.err"
|
|
||||||
[ -e /etc/sysconfig/$name ] && . /etc/sysconfig/$name
|
|
||||||
get_pid() {
|
|
||||||
cat "$pid_file"
|
|
||||||
}
|
|
||||||
is_running() {
|
|
||||||
[ -f "$pid_file" ] && ps | grep -v grep | grep $(get_pid) > /dev/null 2>&1
|
|
||||||
}
|
|
||||||
case "$1" in
|
|
||||||
start)
|
|
||||||
if is_running; then
|
|
||||||
echo "Already started"
|
|
||||||
else
|
|
||||||
echo "Starting $name"
|
|
||||||
{{if .WorkingDirectory}}cd '{{.WorkingDirectory}}'{{end}}
|
|
||||||
$cmd >> "$stdout_log" 2>> "$stderr_log" &
|
|
||||||
echo $! > "$pid_file"
|
|
||||||
if ! is_running; then
|
|
||||||
echo "Unable to start, see $stdout_log and $stderr_log"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
;;
|
|
||||||
stop)
|
|
||||||
if is_running; then
|
|
||||||
echo -n "Stopping $name.."
|
|
||||||
kill $(get_pid)
|
|
||||||
for i in $(seq 1 10)
|
|
||||||
do
|
|
||||||
if ! is_running; then
|
|
||||||
break
|
|
||||||
fi
|
|
||||||
echo -n "."
|
|
||||||
sleep 1
|
|
||||||
done
|
|
||||||
echo
|
|
||||||
if is_running; then
|
|
||||||
echo "Not stopped; may still be shutting down or shutdown may have failed"
|
|
||||||
exit 1
|
|
||||||
else
|
|
||||||
echo "Stopped"
|
|
||||||
if [ -f "$pid_file" ]; then
|
|
||||||
rm "$pid_file"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
echo "Not running"
|
|
||||||
fi
|
|
||||||
;;
|
|
||||||
restart)
|
|
||||||
$0 stop
|
|
||||||
if is_running; then
|
|
||||||
echo "Unable to stop, will not attempt to start"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
$0 start
|
|
||||||
;;
|
|
||||||
status)
|
|
||||||
if is_running; then
|
|
||||||
echo "Running"
|
|
||||||
else
|
|
||||||
echo "Stopped"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
echo "Usage: $0 {start|stop|restart|status}"
|
|
||||||
exit 1
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
exit 0
|
|
||||||
`
|
|
||||||
|
|
||||||
const SystemdScript = `[Unit]
|
|
||||||
Description={{.Description}}
|
|
||||||
ConditionFileIsExecutable={{.Path|cmdEscape}}
|
|
||||||
{{range $i, $dep := .Dependencies}}
|
|
||||||
{{$dep}} {{end}}
|
|
||||||
[Service]
|
|
||||||
LimitNOFILE=65536
|
|
||||||
StartLimitInterval=5
|
|
||||||
StartLimitBurst=10
|
|
||||||
ExecStart={{.Path|cmdEscape}}{{range .Arguments}} {{.|cmd}}{{end}}
|
|
||||||
{{if .ChRoot}}RootDirectory={{.ChRoot|cmd}}{{end}}
|
|
||||||
{{if .WorkingDirectory}}WorkingDirectory={{.WorkingDirectory|cmdEscape}}{{end}}
|
|
||||||
{{if .UserName}}User={{.UserName}}{{end}}
|
|
||||||
{{if .ReloadSignal}}ExecReload=/bin/kill -{{.ReloadSignal}} "$MAINPID"{{end}}
|
|
||||||
{{if .PIDFile}}PIDFile={{.PIDFile|cmd}}{{end}}
|
|
||||||
{{if and .LogOutput .HasOutputFileSupport -}}
|
|
||||||
StandardOutput=file:/var/log/{{.Name}}.out
|
|
||||||
StandardError=file:/var/log/{{.Name}}.err
|
|
||||||
{{- end}}
|
|
||||||
Restart=always
|
Restart=always
|
||||||
RestartSec=120
|
RestartSec=15s
|
||||||
[Install]
|
StandardOutput=append:/var/log/nps/nps.log
|
||||||
WantedBy=multi-user.target
|
ExecStartPre=/bin/echo 'Starting nps'
|
||||||
`
|
ExecStopPost=/bin/echo 'Stopping nps'
|
||||||
|
ExecStart=`
|
||||||
|
install := `[Install]
|
||||||
|
WantedBy=multi-user.target`
|
||||||
|
|
||||||
func UpdateNps() {
|
|
||||||
destPath := downloadLatest("server")
|
|
||||||
//复制文件到对应目录
|
|
||||||
copyStaticFile(destPath, "nps")
|
|
||||||
fmt.Println("Update completed, please restart")
|
|
||||||
}
|
|
||||||
|
|
||||||
func UpdateNpc() {
|
|
||||||
destPath := downloadLatest("client")
|
|
||||||
//复制文件到对应目录
|
|
||||||
copyStaticFile(destPath, "npc")
|
|
||||||
fmt.Println("Update completed, please restart")
|
|
||||||
}
|
|
||||||
|
|
||||||
type release struct {
|
|
||||||
TagName string `json:"tag_name"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func downloadLatest(bin string) string {
|
|
||||||
// get version
|
|
||||||
data, err := http.Get("https://api.github.com/repos/ehang-io/nps/releases/latest")
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err.Error())
|
|
||||||
}
|
|
||||||
b, err := ioutil.ReadAll(data.Body)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
rl := new(release)
|
|
||||||
json.Unmarshal(b, &rl)
|
|
||||||
version := rl.TagName
|
|
||||||
fmt.Println("the latest version is", version)
|
|
||||||
filename := runtime.GOOS + "_" + runtime.GOARCH + "_" + bin + ".tar.gz"
|
|
||||||
// download latest package
|
|
||||||
downloadUrl := fmt.Sprintf("https://ehang.io/nps/releases/download/%s/%s", version, filename)
|
|
||||||
fmt.Println("download package from ", downloadUrl)
|
|
||||||
resp, err := http.Get(downloadUrl)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err.Error())
|
|
||||||
}
|
|
||||||
destPath, err := unpackit.Unpack(resp.Body, "")
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
if bin == "server" {
|
|
||||||
destPath = strings.Replace(destPath, "/web", "", -1)
|
|
||||||
destPath = strings.Replace(destPath, `\web`, "", -1)
|
|
||||||
destPath = strings.Replace(destPath, "/views", "", -1)
|
|
||||||
destPath = strings.Replace(destPath, `\views`, "", -1)
|
|
||||||
} else {
|
|
||||||
destPath = strings.Replace(destPath, `\conf`, "", -1)
|
|
||||||
destPath = strings.Replace(destPath, "/conf", "", -1)
|
|
||||||
}
|
|
||||||
return destPath
|
|
||||||
}
|
|
||||||
|
|
||||||
func copyStaticFile(srcPath, bin string) string {
|
|
||||||
path := common.GetInstallPath()
|
|
||||||
if bin == "nps" {
|
|
||||||
//复制文件到对应目录
|
|
||||||
if err := CopyDir(filepath.Join(srcPath, "web", "views"), filepath.Join(path, "web", "views")); err != nil {
|
|
||||||
log.Fatalln(err)
|
|
||||||
}
|
|
||||||
chMod(filepath.Join(path, "web", "views"), 0766)
|
|
||||||
if err := CopyDir(filepath.Join(srcPath, "web", "static"), filepath.Join(path, "web", "static")); err != nil {
|
|
||||||
log.Fatalln(err)
|
|
||||||
}
|
|
||||||
chMod(filepath.Join(path, "web", "static"), 0766)
|
|
||||||
}
|
|
||||||
binPath, _ := filepath.Abs(os.Args[0])
|
|
||||||
if !common.IsWindows() {
|
|
||||||
if _, err := copyFile(filepath.Join(srcPath, bin), "/usr/bin/"+bin); err != nil {
|
|
||||||
if _, err := copyFile(filepath.Join(srcPath, bin), "/usr/local/bin/"+bin); err != nil {
|
|
||||||
log.Fatalln(err)
|
|
||||||
} else {
|
|
||||||
copyFile(filepath.Join(srcPath, bin), "/usr/local/bin/"+bin+"-update")
|
|
||||||
chMod("/usr/local/bin/"+bin+"-update", 0755)
|
|
||||||
binPath = "/usr/local/bin/" + bin
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
copyFile(filepath.Join(srcPath, bin), "/usr/bin/"+bin+"-update")
|
|
||||||
chMod("/usr/bin/"+bin+"-update", 0755)
|
|
||||||
binPath = "/usr/bin/" + bin
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
copyFile(filepath.Join(srcPath, bin+".exe"), filepath.Join(common.GetAppPath(), bin+"-update.exe"))
|
|
||||||
copyFile(filepath.Join(srcPath, bin+".exe"), filepath.Join(common.GetAppPath(), bin+".exe"))
|
|
||||||
}
|
|
||||||
chMod(binPath, 0755)
|
|
||||||
return binPath
|
|
||||||
}
|
|
||||||
|
|
||||||
func InstallNpc() {
|
|
||||||
path := common.GetInstallPath()
|
|
||||||
if !common.FileExists(path) {
|
|
||||||
err := os.Mkdir(path, 0755)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
copyStaticFile(common.GetAppPath(), "npc")
|
|
||||||
}
|
|
||||||
|
|
||||||
func InstallNps() string {
|
|
||||||
path := common.GetInstallPath()
|
path := common.GetInstallPath()
|
||||||
if common.FileExists(path) {
|
if common.FileExists(path) {
|
||||||
MkidrDirAll(path, "web/static", "web/views")
|
log.Fatalf("the path %s has exist, does not support install", path)
|
||||||
} else {
|
}
|
||||||
MkidrDirAll(path, "conf", "web/static", "web/views")
|
MkidrDirAll(path, "conf", "web/static", "web/views")
|
||||||
// not copy config if the config file is exist
|
//复制文件到对应目录
|
||||||
if err := CopyDir(filepath.Join(common.GetAppPath(), "conf"), filepath.Join(path, "conf")); err != nil {
|
if err := CopyDir(filepath.Join(common.GetAppPath(), "web", "views"), filepath.Join(path, "web", "views")); err != nil {
|
||||||
log.Fatalln(err)
|
log.Fatalln(err)
|
||||||
}
|
}
|
||||||
chMod(filepath.Join(path, "conf"), 0766)
|
if err := CopyDir(filepath.Join(common.GetAppPath(), "web", "static"), filepath.Join(path, "web", "static")); err != nil {
|
||||||
|
log.Fatalln(err)
|
||||||
|
}
|
||||||
|
if err := CopyDir(filepath.Join(common.GetAppPath(), "conf"), filepath.Join(path, "conf")); err != nil {
|
||||||
|
log.Fatalln(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !common.IsWindows() {
|
||||||
|
if _, err := copyFile(filepath.Join(common.GetAppPath(), "nps"), "/usr/bin/nps"); err != nil {
|
||||||
|
if _, err := copyFile(filepath.Join(common.GetAppPath(), "nps"), "/usr/local/bin/nps"); err != nil {
|
||||||
|
log.Fatalln(err)
|
||||||
|
} else {
|
||||||
|
os.Chmod("/usr/local/bin/nps", 0755)
|
||||||
|
service += "/usr/local/bin/nps"
|
||||||
|
log.Println("Executable files have been copied to", "/usr/local/bin/nps")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
os.Chmod("/usr/bin/nps", 0755)
|
||||||
|
service += "/usr/bin/nps"
|
||||||
|
log.Println("Executable files have been copied to", "/usr/bin/nps")
|
||||||
|
}
|
||||||
|
systemd := unit + "\n\n" + service + "\n\n" + install
|
||||||
|
_ = os.Remove("/usr/lib/systemd/system/nps.service")
|
||||||
|
err := ioutil.WriteFile("/usr/lib/systemd/system/nps.service", []byte(systemd), 0644)
|
||||||
|
if err != nil {
|
||||||
|
log.Println("Write systemd service err ", err)
|
||||||
|
}
|
||||||
|
_ = os.Mkdir("/var/log/nps", 644)
|
||||||
}
|
}
|
||||||
binPath := copyStaticFile(common.GetAppPath(), "nps")
|
|
||||||
log.Println("install ok!")
|
log.Println("install ok!")
|
||||||
log.Println("Static files and configuration files in the current directory will be useless")
|
log.Println("Static files and configuration files in the current directory will be useless")
|
||||||
log.Println("The new configuration file is located in", path, "you can edit them")
|
log.Println("The new configuration file is located in", path, "you can edit them")
|
||||||
if !common.IsWindows() {
|
if !common.IsWindows() {
|
||||||
log.Println(`You can start with:
|
log.Println(`You can start with:
|
||||||
nps start|stop|restart|uninstall|update or nps-update update
|
sudo systemctl enable|disable|start|stop|restart|status nps
|
||||||
|
or:
|
||||||
|
nps test|start|stop|restart|status
|
||||||
anywhere!`)
|
anywhere!`)
|
||||||
} else {
|
} else {
|
||||||
log.Println(`You can copy executable files to any directory and start working with:
|
log.Println(`You can copy executable files to any directory and start working with:
|
||||||
nps.exe start|stop|restart|uninstall|update or nps-update.exe update
|
nps.exe test|start|stop|restart|status
|
||||||
now!`)
|
now!`)
|
||||||
}
|
}
|
||||||
chMod(common.GetLogPath(), 0777)
|
|
||||||
return binPath
|
|
||||||
}
|
}
|
||||||
func MkidrDirAll(path string, v ...string) {
|
func MkidrDirAll(path string, v ...string) {
|
||||||
for _, item := range v {
|
for _, item := range v {
|
||||||
@ -300,9 +119,6 @@ func CopyDir(srcPath string, destPath string) error {
|
|||||||
destNewPath := strings.Replace(path, srcPath, destPath, -1)
|
destNewPath := strings.Replace(path, srcPath, destPath, -1)
|
||||||
log.Println("copy file ::" + path + " to " + destNewPath)
|
log.Println("copy file ::" + path + " to " + destNewPath)
|
||||||
copyFile(path, destNewPath)
|
copyFile(path, destNewPath)
|
||||||
if !common.IsWindows() {
|
|
||||||
chMod(destNewPath, 0766)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
@ -355,9 +171,3 @@ func pathExists(path string) (bool, error) {
|
|||||||
}
|
}
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func chMod(name string, mode os.FileMode) {
|
|
||||||
if !common.IsWindows() {
|
|
||||||
os.Chmod(name, mode)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
32
lib/mux/bytes.go
Normal file
32
lib/mux/bytes.go
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
package mux
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/binary"
|
||||||
|
"io"
|
||||||
|
)
|
||||||
|
|
||||||
|
//write bytes with int32 length
|
||||||
|
func WriteLenBytes(buf []byte, w io.Writer) (int, error) {
|
||||||
|
raw := bytes.NewBuffer([]byte{})
|
||||||
|
if err := binary.Write(raw, binary.LittleEndian, int32(len(buf))); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
if err := binary.Write(raw, binary.LittleEndian, buf); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return w.Write(raw.Bytes())
|
||||||
|
}
|
||||||
|
|
||||||
|
//read bytes by length
|
||||||
|
func ReadLenBytes(buf []byte, r io.Reader) (int, error) {
|
||||||
|
var l uint32
|
||||||
|
var err error
|
||||||
|
if binary.Read(r, binary.LittleEndian, &l) != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
if _, err = io.ReadFull(r, buf[:l]); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return int(l), nil
|
||||||
|
}
|
635
lib/mux/conn.go
Normal file
635
lib/mux/conn.go
Normal file
@ -0,0 +1,635 @@
|
|||||||
|
package mux
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"io"
|
||||||
|
"math"
|
||||||
|
"net"
|
||||||
|
"runtime"
|
||||||
|
"sync"
|
||||||
|
"sync/atomic"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/cnlh/nps/lib/common"
|
||||||
|
)
|
||||||
|
|
||||||
|
type conn struct {
|
||||||
|
net.Conn
|
||||||
|
getStatusCh chan struct{}
|
||||||
|
connStatusOkCh chan struct{}
|
||||||
|
connStatusFailCh chan struct{}
|
||||||
|
connId int32
|
||||||
|
isClose bool
|
||||||
|
closeFlag bool // close conn flag
|
||||||
|
receiveWindow *ReceiveWindow
|
||||||
|
sendWindow *SendWindow
|
||||||
|
once sync.Once
|
||||||
|
//label string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewConn(connId int32, mux *Mux, label ...string) *conn {
|
||||||
|
c := &conn{
|
||||||
|
getStatusCh: make(chan struct{}),
|
||||||
|
connStatusOkCh: make(chan struct{}),
|
||||||
|
connStatusFailCh: make(chan struct{}),
|
||||||
|
connId: connId,
|
||||||
|
receiveWindow: new(ReceiveWindow),
|
||||||
|
sendWindow: new(SendWindow),
|
||||||
|
once: sync.Once{},
|
||||||
|
}
|
||||||
|
//if len(label) > 0 {
|
||||||
|
// c.label = label[0]
|
||||||
|
//}
|
||||||
|
c.receiveWindow.New(mux)
|
||||||
|
c.sendWindow.New(mux)
|
||||||
|
//logm := &connLog{
|
||||||
|
// startTime: time.Now(),
|
||||||
|
// isClose: false,
|
||||||
|
// logs: []string{c.label + "new conn success"},
|
||||||
|
//}
|
||||||
|
//setM(label[0], int(connId), logm)
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *conn) Read(buf []byte) (n int, err error) {
|
||||||
|
if s.isClose || buf == nil {
|
||||||
|
return 0, errors.New("the conn has closed")
|
||||||
|
}
|
||||||
|
if len(buf) == 0 {
|
||||||
|
return 0, nil
|
||||||
|
}
|
||||||
|
// waiting for takeout from receive window finish or timeout
|
||||||
|
//now := time.Now()
|
||||||
|
n, err = s.receiveWindow.Read(buf, s.connId)
|
||||||
|
//t := time.Now().Sub(now)
|
||||||
|
//if t.Seconds() > 0.5 {
|
||||||
|
//logs.Warn("conn read long", n, t.Seconds())
|
||||||
|
//}
|
||||||
|
//var errstr string
|
||||||
|
//if err == nil {
|
||||||
|
// errstr = "err:nil"
|
||||||
|
//} else {
|
||||||
|
// errstr = err.Error()
|
||||||
|
//}
|
||||||
|
//d := getM(s.label, int(s.connId))
|
||||||
|
//d.logs = append(d.logs, s.label+"read "+strconv.Itoa(n)+" "+errstr+" "+string(buf[:100]))
|
||||||
|
//setM(s.label, int(s.connId), d)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *conn) Write(buf []byte) (n int, err error) {
|
||||||
|
if s.isClose {
|
||||||
|
return 0, errors.New("the conn has closed")
|
||||||
|
}
|
||||||
|
if s.closeFlag {
|
||||||
|
//s.Close()
|
||||||
|
return 0, errors.New("io: write on closed conn")
|
||||||
|
}
|
||||||
|
if len(buf) == 0 {
|
||||||
|
return 0, nil
|
||||||
|
}
|
||||||
|
//logs.Warn("write buf", len(buf))
|
||||||
|
//now := time.Now()
|
||||||
|
n, err = s.sendWindow.WriteFull(buf, s.connId)
|
||||||
|
//t := time.Now().Sub(now)
|
||||||
|
//if t.Seconds() > 0.5 {
|
||||||
|
// logs.Warn("conn write long", n, t.Seconds())
|
||||||
|
//}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *conn) Close() (err error) {
|
||||||
|
s.once.Do(s.closeProcess)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *conn) closeProcess() {
|
||||||
|
s.isClose = true
|
||||||
|
s.receiveWindow.mux.connMap.Delete(s.connId)
|
||||||
|
if !s.receiveWindow.mux.IsClose {
|
||||||
|
// if server or user close the conn while reading, will get a io.EOF
|
||||||
|
// and this Close method will be invoke, send this signal to close other side
|
||||||
|
s.receiveWindow.mux.sendInfo(common.MUX_CONN_CLOSE, s.connId, nil)
|
||||||
|
}
|
||||||
|
s.sendWindow.CloseWindow()
|
||||||
|
s.receiveWindow.CloseWindow()
|
||||||
|
//d := getM(s.label, int(s.connId))
|
||||||
|
//d.isClose = true
|
||||||
|
//d.logs = append(d.logs, s.label+"close "+time.Now().String())
|
||||||
|
//setM(s.label, int(s.connId), d)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *conn) LocalAddr() net.Addr {
|
||||||
|
return s.receiveWindow.mux.conn.LocalAddr()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *conn) RemoteAddr() net.Addr {
|
||||||
|
return s.receiveWindow.mux.conn.RemoteAddr()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *conn) SetDeadline(t time.Time) error {
|
||||||
|
_ = s.SetReadDeadline(t)
|
||||||
|
_ = s.SetWriteDeadline(t)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *conn) SetReadDeadline(t time.Time) error {
|
||||||
|
s.receiveWindow.SetTimeOut(t)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *conn) SetWriteDeadline(t time.Time) error {
|
||||||
|
s.sendWindow.SetTimeOut(t)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type window struct {
|
||||||
|
remainingWait uint64 // 64bit alignment
|
||||||
|
off uint32
|
||||||
|
maxSize uint32
|
||||||
|
closeOp bool
|
||||||
|
closeOpCh chan struct{}
|
||||||
|
mux *Mux
|
||||||
|
}
|
||||||
|
|
||||||
|
func (Self *window) unpack(ptrs uint64) (remaining, wait uint32) {
|
||||||
|
const mask = 1<<dequeueBits - 1
|
||||||
|
remaining = uint32((ptrs >> dequeueBits) & mask)
|
||||||
|
wait = uint32(ptrs & mask)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (Self *window) pack(remaining, wait uint32) uint64 {
|
||||||
|
const mask = 1<<dequeueBits - 1
|
||||||
|
return (uint64(remaining) << dequeueBits) |
|
||||||
|
uint64(wait&mask)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (Self *window) New() {
|
||||||
|
Self.closeOpCh = make(chan struct{}, 2)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (Self *window) CloseWindow() {
|
||||||
|
if !Self.closeOp {
|
||||||
|
Self.closeOp = true
|
||||||
|
Self.closeOpCh <- struct{}{}
|
||||||
|
Self.closeOpCh <- struct{}{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type ReceiveWindow struct {
|
||||||
|
window
|
||||||
|
bufQueue ReceiveWindowQueue
|
||||||
|
element *common.ListElement
|
||||||
|
count int8
|
||||||
|
once sync.Once
|
||||||
|
}
|
||||||
|
|
||||||
|
func (Self *ReceiveWindow) New(mux *Mux) {
|
||||||
|
// initial a window for receive
|
||||||
|
Self.bufQueue.New()
|
||||||
|
Self.element = common.ListElementPool.Get()
|
||||||
|
Self.maxSize = common.MAXIMUM_SEGMENT_SIZE * 10
|
||||||
|
Self.mux = mux
|
||||||
|
Self.window.New()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (Self *ReceiveWindow) remainingSize(delta uint16) (n uint32) {
|
||||||
|
// receive window remaining
|
||||||
|
l := int64(atomic.LoadUint32(&Self.maxSize)) - int64(Self.bufQueue.Len())
|
||||||
|
l -= int64(delta)
|
||||||
|
if l > 0 {
|
||||||
|
n = uint32(l)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (Self *ReceiveWindow) calcSize() {
|
||||||
|
// calculating maximum receive window size
|
||||||
|
if Self.count == 0 {
|
||||||
|
//logs.Warn("ping, bw", Self.mux.latency, Self.bw.Get())
|
||||||
|
conns := Self.mux.connMap.Size()
|
||||||
|
n := uint32(math.Float64frombits(atomic.LoadUint64(&Self.mux.latency)) *
|
||||||
|
Self.mux.bw.Get() / float64(conns))
|
||||||
|
if n < common.MAXIMUM_SEGMENT_SIZE*10 {
|
||||||
|
n = common.MAXIMUM_SEGMENT_SIZE * 10
|
||||||
|
}
|
||||||
|
bufLen := Self.bufQueue.Len()
|
||||||
|
if n < bufLen {
|
||||||
|
n = bufLen
|
||||||
|
}
|
||||||
|
if n < Self.maxSize/2 {
|
||||||
|
n = Self.maxSize / 2
|
||||||
|
}
|
||||||
|
// set the minimal size
|
||||||
|
if n > 2*Self.maxSize {
|
||||||
|
n = 2 * Self.maxSize
|
||||||
|
}
|
||||||
|
if n > (common.MAXIMUM_WINDOW_SIZE / uint32(conns)) {
|
||||||
|
n = common.MAXIMUM_WINDOW_SIZE / uint32(conns)
|
||||||
|
}
|
||||||
|
// set the maximum size
|
||||||
|
//logs.Warn("n", n)
|
||||||
|
atomic.StoreUint32(&Self.maxSize, n)
|
||||||
|
Self.count = -10
|
||||||
|
}
|
||||||
|
Self.count += 1
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (Self *ReceiveWindow) Write(buf []byte, l uint16, part bool, id int32) (err error) {
|
||||||
|
if Self.closeOp {
|
||||||
|
return errors.New("conn.receiveWindow: write on closed window")
|
||||||
|
}
|
||||||
|
element, err := NewListElement(buf, l, part)
|
||||||
|
//logs.Warn("push the buf", len(buf), l, (&element).l)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
Self.calcSize() // calculate the max window size
|
||||||
|
var wait uint32
|
||||||
|
start:
|
||||||
|
ptrs := atomic.LoadUint64(&Self.remainingWait)
|
||||||
|
_, wait = Self.unpack(ptrs)
|
||||||
|
newRemaining := Self.remainingSize(l)
|
||||||
|
// calculate the remaining window size now, plus the element we will push
|
||||||
|
if newRemaining == 0 {
|
||||||
|
//logs.Warn("window full true", remaining)
|
||||||
|
wait = 1
|
||||||
|
}
|
||||||
|
if !atomic.CompareAndSwapUint64(&Self.remainingWait, ptrs, Self.pack(0, wait)) {
|
||||||
|
goto start
|
||||||
|
// another goroutine change the status, make sure shall we need wait
|
||||||
|
}
|
||||||
|
Self.bufQueue.Push(element)
|
||||||
|
// status check finish, now we can push the element into the queue
|
||||||
|
if wait == 0 {
|
||||||
|
Self.mux.sendInfo(common.MUX_MSG_SEND_OK, id, Self.maxSize, newRemaining)
|
||||||
|
// send the remaining window size, not including zero size
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (Self *ReceiveWindow) Read(p []byte, id int32) (n int, err error) {
|
||||||
|
if Self.closeOp {
|
||||||
|
return 0, io.EOF // receive close signal, returns eof
|
||||||
|
}
|
||||||
|
pOff := 0
|
||||||
|
l := 0
|
||||||
|
//logs.Warn("receive window read off, element.l", Self.off, Self.element.l)
|
||||||
|
copyData:
|
||||||
|
if Self.off == uint32(Self.element.L) {
|
||||||
|
// on the first Read method invoked, Self.off and Self.element.l
|
||||||
|
// both zero value
|
||||||
|
common.ListElementPool.Put(Self.element)
|
||||||
|
if Self.closeOp {
|
||||||
|
return 0, io.EOF
|
||||||
|
}
|
||||||
|
Self.element, err = Self.bufQueue.Pop()
|
||||||
|
// if the queue is empty, Pop method will wait until one element push
|
||||||
|
// into the queue successful, or timeout.
|
||||||
|
// timer start on timeout parameter is set up ,
|
||||||
|
// reset to 60s if timeout and data still available
|
||||||
|
Self.off = 0
|
||||||
|
if err != nil {
|
||||||
|
return // queue receive stop or time out, break the loop and return
|
||||||
|
}
|
||||||
|
//logs.Warn("pop element", Self.element.l, Self.element.part)
|
||||||
|
}
|
||||||
|
l = copy(p[pOff:], Self.element.Buf[Self.off:Self.element.L])
|
||||||
|
pOff += l
|
||||||
|
Self.off += uint32(l)
|
||||||
|
//logs.Warn("window read length buf len", Self.readLength, Self.bufQueue.Len())
|
||||||
|
n += l
|
||||||
|
l = 0
|
||||||
|
if Self.off == uint32(Self.element.L) {
|
||||||
|
//logs.Warn("put the element end ", string(Self.element.buf[:15]))
|
||||||
|
common.WindowBuff.Put(Self.element.Buf)
|
||||||
|
Self.sendStatus(id, Self.element.L)
|
||||||
|
// check the window full status
|
||||||
|
}
|
||||||
|
if pOff < len(p) && Self.element.Part {
|
||||||
|
// element is a part of the segments, trying to fill up buf p
|
||||||
|
goto copyData
|
||||||
|
}
|
||||||
|
return // buf p is full or all of segments in buf, return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (Self *ReceiveWindow) sendStatus(id int32, l uint16) {
|
||||||
|
var remaining, wait uint32
|
||||||
|
for {
|
||||||
|
ptrs := atomic.LoadUint64(&Self.remainingWait)
|
||||||
|
remaining, wait = Self.unpack(ptrs)
|
||||||
|
remaining += uint32(l)
|
||||||
|
if atomic.CompareAndSwapUint64(&Self.remainingWait, ptrs, Self.pack(remaining, 0)) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
runtime.Gosched()
|
||||||
|
// another goroutine change remaining or wait status, make sure
|
||||||
|
// we need acknowledge other side
|
||||||
|
}
|
||||||
|
// now we get the current window status success
|
||||||
|
if wait == 1 {
|
||||||
|
//logs.Warn("send the wait status", remaining)
|
||||||
|
Self.mux.sendInfo(common.MUX_MSG_SEND_OK, id, atomic.LoadUint32(&Self.maxSize), remaining)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (Self *ReceiveWindow) SetTimeOut(t time.Time) {
|
||||||
|
// waiting for FIFO queue Pop method
|
||||||
|
Self.bufQueue.SetTimeOut(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (Self *ReceiveWindow) Stop() {
|
||||||
|
// queue has no more data to push, so unblock pop method
|
||||||
|
Self.once.Do(Self.bufQueue.Stop)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (Self *ReceiveWindow) CloseWindow() {
|
||||||
|
Self.window.CloseWindow()
|
||||||
|
Self.Stop()
|
||||||
|
Self.release()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (Self *ReceiveWindow) release() {
|
||||||
|
//if Self.element != nil {
|
||||||
|
// if Self.element.Buf != nil {
|
||||||
|
// common.WindowBuff.Put(Self.element.Buf)
|
||||||
|
// }
|
||||||
|
// common.ListElementPool.Put(Self.element)
|
||||||
|
//}
|
||||||
|
for {
|
||||||
|
Self.element = Self.bufQueue.TryPop()
|
||||||
|
if Self.element == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if Self.element.Buf != nil {
|
||||||
|
common.WindowBuff.Put(Self.element.Buf)
|
||||||
|
}
|
||||||
|
common.ListElementPool.Put(Self.element)
|
||||||
|
} // release resource
|
||||||
|
}
|
||||||
|
|
||||||
|
type SendWindow struct {
|
||||||
|
window
|
||||||
|
buf []byte
|
||||||
|
setSizeCh chan struct{}
|
||||||
|
timeout time.Time
|
||||||
|
}
|
||||||
|
|
||||||
|
func (Self *SendWindow) New(mux *Mux) {
|
||||||
|
Self.setSizeCh = make(chan struct{})
|
||||||
|
Self.maxSize = common.MAXIMUM_SEGMENT_SIZE * 10
|
||||||
|
atomic.AddUint64(&Self.remainingWait, uint64(common.MAXIMUM_SEGMENT_SIZE*10)<<dequeueBits)
|
||||||
|
Self.mux = mux
|
||||||
|
Self.window.New()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (Self *SendWindow) SetSendBuf(buf []byte) {
|
||||||
|
// send window buff from conn write method, set it to send window
|
||||||
|
Self.buf = buf
|
||||||
|
Self.off = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (Self *SendWindow) SetSize(windowSize, newRemaining uint32) (closed bool) {
|
||||||
|
// set the window size from receive window
|
||||||
|
defer func() {
|
||||||
|
if recover() != nil {
|
||||||
|
closed = true
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
if Self.closeOp {
|
||||||
|
close(Self.setSizeCh)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
//logs.Warn("set send window size to ", windowSize, newRemaining)
|
||||||
|
var remaining, wait, newWait uint32
|
||||||
|
for {
|
||||||
|
ptrs := atomic.LoadUint64(&Self.remainingWait)
|
||||||
|
remaining, wait = Self.unpack(ptrs)
|
||||||
|
if remaining == newRemaining {
|
||||||
|
//logs.Warn("waiting for another window size")
|
||||||
|
return false // waiting for receive another usable window size
|
||||||
|
}
|
||||||
|
if newRemaining == 0 && wait == 1 {
|
||||||
|
newWait = 1 // keep the wait status,
|
||||||
|
// also if newRemaining is not zero, change wait to 0
|
||||||
|
}
|
||||||
|
if atomic.CompareAndSwapUint64(&Self.remainingWait, ptrs, Self.pack(newRemaining, newWait)) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
// anther goroutine change wait status or window size
|
||||||
|
}
|
||||||
|
if wait == 1 {
|
||||||
|
// send window into the wait status, need notice the channel
|
||||||
|
//logs.Warn("send window remaining size is 0")
|
||||||
|
Self.allow()
|
||||||
|
}
|
||||||
|
// send window not into the wait status, so just do slide
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (Self *SendWindow) allow() {
|
||||||
|
select {
|
||||||
|
case Self.setSizeCh <- struct{}{}:
|
||||||
|
//logs.Warn("send window remaining size is 0 finish")
|
||||||
|
return
|
||||||
|
case <-Self.closeOpCh:
|
||||||
|
close(Self.setSizeCh)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (Self *SendWindow) sent(sentSize uint32) {
|
||||||
|
atomic.AddUint64(&Self.remainingWait, ^(uint64(sentSize)<<dequeueBits - 1))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (Self *SendWindow) WriteTo() (p []byte, sendSize uint32, part bool, err error) {
|
||||||
|
// returns buf segments, return only one segments, need a loop outside
|
||||||
|
// until err = io.EOF
|
||||||
|
if Self.closeOp {
|
||||||
|
return nil, 0, false, errors.New("conn.writeWindow: window closed")
|
||||||
|
}
|
||||||
|
if Self.off == uint32(len(Self.buf)) {
|
||||||
|
return nil, 0, false, io.EOF
|
||||||
|
// send window buff is drain, return eof and get another one
|
||||||
|
}
|
||||||
|
var remaining uint32
|
||||||
|
start:
|
||||||
|
ptrs := atomic.LoadUint64(&Self.remainingWait)
|
||||||
|
remaining, _ = Self.unpack(ptrs)
|
||||||
|
if remaining == 0 {
|
||||||
|
if !atomic.CompareAndSwapUint64(&Self.remainingWait, ptrs, Self.pack(0, 1)) {
|
||||||
|
goto start // another goroutine change the window, try again
|
||||||
|
}
|
||||||
|
// into the wait status
|
||||||
|
//logs.Warn("send window into wait status")
|
||||||
|
err = Self.waitReceiveWindow()
|
||||||
|
if err != nil {
|
||||||
|
return nil, 0, false, err
|
||||||
|
}
|
||||||
|
//logs.Warn("rem into wait finish")
|
||||||
|
goto start
|
||||||
|
}
|
||||||
|
// there are still remaining window
|
||||||
|
//logs.Warn("rem", remaining)
|
||||||
|
if len(Self.buf[Self.off:]) > common.MAXIMUM_SEGMENT_SIZE {
|
||||||
|
sendSize = common.MAXIMUM_SEGMENT_SIZE
|
||||||
|
//logs.Warn("cut buf by mss")
|
||||||
|
} else {
|
||||||
|
sendSize = uint32(len(Self.buf[Self.off:]))
|
||||||
|
}
|
||||||
|
if remaining < sendSize {
|
||||||
|
// usable window size is small than
|
||||||
|
// window MAXIMUM_SEGMENT_SIZE or send buf left
|
||||||
|
sendSize = remaining
|
||||||
|
//logs.Warn("cut buf by remainingsize", sendSize, len(Self.buf[Self.off:]))
|
||||||
|
}
|
||||||
|
//logs.Warn("send size", sendSize)
|
||||||
|
if sendSize < uint32(len(Self.buf[Self.off:])) {
|
||||||
|
part = true
|
||||||
|
}
|
||||||
|
p = Self.buf[Self.off : sendSize+Self.off]
|
||||||
|
Self.off += sendSize
|
||||||
|
Self.sent(sendSize)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (Self *SendWindow) waitReceiveWindow() (err error) {
|
||||||
|
t := Self.timeout.Sub(time.Now())
|
||||||
|
if t < 0 {
|
||||||
|
t = time.Minute * 5
|
||||||
|
}
|
||||||
|
timer := time.NewTimer(t)
|
||||||
|
defer timer.Stop()
|
||||||
|
// waiting for receive usable window size, or timeout
|
||||||
|
select {
|
||||||
|
case _, ok := <-Self.setSizeCh:
|
||||||
|
if !ok {
|
||||||
|
return errors.New("conn.writeWindow: window closed")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
case <-timer.C:
|
||||||
|
return errors.New("conn.writeWindow: write to time out")
|
||||||
|
case <-Self.closeOpCh:
|
||||||
|
return errors.New("conn.writeWindow: window closed")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (Self *SendWindow) WriteFull(buf []byte, id int32) (n int, err error) {
|
||||||
|
Self.SetSendBuf(buf) // set the buf to send window
|
||||||
|
//logs.Warn("set the buf to send window")
|
||||||
|
var bufSeg []byte
|
||||||
|
var part bool
|
||||||
|
var l uint32
|
||||||
|
for {
|
||||||
|
bufSeg, l, part, err = Self.WriteTo()
|
||||||
|
//logs.Warn("buf seg", len(bufSeg), part, err)
|
||||||
|
// get the buf segments from send window
|
||||||
|
if bufSeg == nil && part == false && err == io.EOF {
|
||||||
|
// send window is drain, break the loop
|
||||||
|
err = nil
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
n += int(l)
|
||||||
|
l = 0
|
||||||
|
if part {
|
||||||
|
Self.mux.sendInfo(common.MUX_NEW_MSG_PART, id, bufSeg)
|
||||||
|
} else {
|
||||||
|
Self.mux.sendInfo(common.MUX_NEW_MSG, id, bufSeg)
|
||||||
|
//logs.Warn("buf seg sent", len(bufSeg), part, err)
|
||||||
|
}
|
||||||
|
// send to other side, not send nil data to other side
|
||||||
|
}
|
||||||
|
//logs.Warn("buf seg write success")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (Self *SendWindow) SetTimeOut(t time.Time) {
|
||||||
|
// waiting for receive a receive window size
|
||||||
|
Self.timeout = t
|
||||||
|
}
|
||||||
|
|
||||||
|
//type bandwidth struct {
|
||||||
|
// readStart time.Time
|
||||||
|
// lastReadStart time.Time
|
||||||
|
// readEnd time.Time
|
||||||
|
// lastReadEnd time.Time
|
||||||
|
// bufLength int
|
||||||
|
// lastBufLength int
|
||||||
|
// count int8
|
||||||
|
// readBW float64
|
||||||
|
// writeBW float64
|
||||||
|
// readBandwidth float64
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//func (Self *bandwidth) StartRead() {
|
||||||
|
// Self.lastReadStart, Self.readStart = Self.readStart, time.Now()
|
||||||
|
// if !Self.lastReadStart.IsZero() {
|
||||||
|
// if Self.count == -5 {
|
||||||
|
// Self.calcBandWidth()
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//func (Self *bandwidth) EndRead() {
|
||||||
|
// Self.lastReadEnd, Self.readEnd = Self.readEnd, time.Now()
|
||||||
|
// if Self.count == -5 {
|
||||||
|
// Self.calcWriteBandwidth()
|
||||||
|
// }
|
||||||
|
// if Self.count == 0 {
|
||||||
|
// Self.calcReadBandwidth()
|
||||||
|
// Self.count = -6
|
||||||
|
// }
|
||||||
|
// Self.count += 1
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//func (Self *bandwidth) SetCopySize(n int) {
|
||||||
|
// // must be invoke between StartRead and EndRead
|
||||||
|
// Self.lastBufLength, Self.bufLength = Self.bufLength, n
|
||||||
|
//}
|
||||||
|
//// calculating
|
||||||
|
//// start end start end
|
||||||
|
//// read read
|
||||||
|
//// write
|
||||||
|
//
|
||||||
|
//func (Self *bandwidth) calcBandWidth() {
|
||||||
|
// t := Self.readStart.Sub(Self.lastReadStart)
|
||||||
|
// if Self.lastBufLength >= 32768 {
|
||||||
|
// Self.readBandwidth = float64(Self.lastBufLength) / t.Seconds()
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//func (Self *bandwidth) calcReadBandwidth() {
|
||||||
|
// // Bandwidth between nps and npc
|
||||||
|
// readTime := Self.readEnd.Sub(Self.readStart)
|
||||||
|
// Self.readBW = float64(Self.bufLength) / readTime.Seconds()
|
||||||
|
// //logs.Warn("calc read bw", Self.readBW, Self.bufLength, readTime.Seconds())
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//func (Self *bandwidth) calcWriteBandwidth() {
|
||||||
|
// // Bandwidth between nps and user, npc and application
|
||||||
|
// writeTime := Self.readStart.Sub(Self.lastReadEnd)
|
||||||
|
// Self.writeBW = float64(Self.lastBufLength) / writeTime.Seconds()
|
||||||
|
// //logs.Warn("calc write bw", Self.writeBW, Self.bufLength, writeTime.Seconds())
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//func (Self *bandwidth) Get() (bw float64) {
|
||||||
|
// // The zero value, 0 for numeric types
|
||||||
|
// if Self.writeBW == 0 && Self.readBW == 0 {
|
||||||
|
// //logs.Warn("bw both 0")
|
||||||
|
// return 100
|
||||||
|
// }
|
||||||
|
// if Self.writeBW == 0 && Self.readBW != 0 {
|
||||||
|
// return Self.readBW
|
||||||
|
// }
|
||||||
|
// if Self.readBW == 0 && Self.writeBW != 0 {
|
||||||
|
// return Self.writeBW
|
||||||
|
// }
|
||||||
|
// return Self.readBandwidth
|
||||||
|
//}
|
75
lib/mux/map.go
Normal file
75
lib/mux/map.go
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
package mux
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
type connMap struct {
|
||||||
|
connMap map[int32]*conn
|
||||||
|
//closeCh chan struct{}
|
||||||
|
sync.RWMutex
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewConnMap() *connMap {
|
||||||
|
connMap := &connMap{
|
||||||
|
connMap: make(map[int32]*conn),
|
||||||
|
//closeCh: make(chan struct{}),
|
||||||
|
}
|
||||||
|
//go connMap.clean()
|
||||||
|
return connMap
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *connMap) Size() (n int) {
|
||||||
|
s.Lock()
|
||||||
|
n = len(s.connMap)
|
||||||
|
s.Unlock()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *connMap) Get(id int32) (*conn, bool) {
|
||||||
|
s.Lock()
|
||||||
|
v, ok := s.connMap[id]
|
||||||
|
s.Unlock()
|
||||||
|
if ok && v != nil {
|
||||||
|
return v, true
|
||||||
|
}
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *connMap) Set(id int32, v *conn) {
|
||||||
|
s.Lock()
|
||||||
|
s.connMap[id] = v
|
||||||
|
s.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *connMap) Close() {
|
||||||
|
//s.closeCh <- struct{}{} // stop the clean goroutine first
|
||||||
|
for _, v := range s.connMap {
|
||||||
|
v.Close() // close all the connections in the mux
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *connMap) Delete(id int32) {
|
||||||
|
s.Lock()
|
||||||
|
delete(s.connMap, id)
|
||||||
|
s.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
//func (s *connMap) clean() {
|
||||||
|
// ticker := time.NewTimer(time.Minute * 1)
|
||||||
|
// for {
|
||||||
|
// select {
|
||||||
|
// case <-ticker.C:
|
||||||
|
// s.Lock()
|
||||||
|
// for _, v := range s.connMap {
|
||||||
|
// if v.isClose {
|
||||||
|
// delete(s.connMap, v.connId)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// s.Unlock()
|
||||||
|
// case <-s.closeCh:
|
||||||
|
// ticker.Stop()
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//}
|
508
lib/mux/mux.go
Normal file
508
lib/mux/mux.go
Normal file
@ -0,0 +1,508 @@
|
|||||||
|
package mux
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"io"
|
||||||
|
"math"
|
||||||
|
"net"
|
||||||
|
"sync/atomic"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/astaxie/beego/logs"
|
||||||
|
"github.com/cnlh/nps/lib/common"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Mux struct {
|
||||||
|
latency uint64 // we store latency in bits, but it's float64
|
||||||
|
net.Listener
|
||||||
|
conn net.Conn
|
||||||
|
connMap *connMap
|
||||||
|
newConnCh chan *conn
|
||||||
|
id int32
|
||||||
|
closeChan chan struct{}
|
||||||
|
IsClose bool
|
||||||
|
pingOk uint32
|
||||||
|
counter *latencyCounter
|
||||||
|
bw *bandwidth
|
||||||
|
pingCh chan []byte
|
||||||
|
pingCheckTime uint32
|
||||||
|
connType string
|
||||||
|
writeQueue PriorityQueue
|
||||||
|
newConnQueue ConnQueue
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewMux(c net.Conn, connType string) *Mux {
|
||||||
|
//c.(*net.TCPConn).SetReadBuffer(0)
|
||||||
|
//c.(*net.TCPConn).SetWriteBuffer(0)
|
||||||
|
m := &Mux{
|
||||||
|
conn: c,
|
||||||
|
connMap: NewConnMap(),
|
||||||
|
id: 0,
|
||||||
|
closeChan: make(chan struct{}, 1),
|
||||||
|
newConnCh: make(chan *conn),
|
||||||
|
bw: new(bandwidth),
|
||||||
|
IsClose: false,
|
||||||
|
connType: connType,
|
||||||
|
pingCh: make(chan []byte),
|
||||||
|
counter: newLatencyCounter(),
|
||||||
|
}
|
||||||
|
m.writeQueue.New()
|
||||||
|
m.newConnQueue.New()
|
||||||
|
//read session by flag
|
||||||
|
m.readSession()
|
||||||
|
//ping
|
||||||
|
m.ping()
|
||||||
|
m.pingReturn()
|
||||||
|
m.writeSession()
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Mux) NewConn() (*conn, error) {
|
||||||
|
if s.IsClose {
|
||||||
|
return nil, errors.New("the mux has closed")
|
||||||
|
}
|
||||||
|
conn := NewConn(s.getId(), s, "nps ")
|
||||||
|
//it must be set before send
|
||||||
|
s.connMap.Set(conn.connId, conn)
|
||||||
|
s.sendInfo(common.MUX_NEW_CONN, conn.connId, nil)
|
||||||
|
//set a timer timeout 30 second
|
||||||
|
timer := time.NewTimer(time.Minute * 2)
|
||||||
|
defer timer.Stop()
|
||||||
|
select {
|
||||||
|
case <-conn.connStatusOkCh:
|
||||||
|
return conn, nil
|
||||||
|
case <-conn.connStatusFailCh:
|
||||||
|
case <-timer.C:
|
||||||
|
}
|
||||||
|
return nil, errors.New("create connection fail,the server refused the connection")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Mux) Accept() (net.Conn, error) {
|
||||||
|
if s.IsClose {
|
||||||
|
return nil, errors.New("accpet error,the mux has closed")
|
||||||
|
}
|
||||||
|
conn := <-s.newConnCh
|
||||||
|
if conn == nil {
|
||||||
|
return nil, errors.New("accpet error,the conn has closed")
|
||||||
|
}
|
||||||
|
return conn, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Mux) Addr() net.Addr {
|
||||||
|
return s.conn.LocalAddr()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Mux) sendInfo(flag uint8, id int32, data ...interface{}) {
|
||||||
|
if s.IsClose {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var err error
|
||||||
|
pack := common.MuxPack.Get()
|
||||||
|
err = pack.NewPac(flag, id, data...)
|
||||||
|
if err != nil {
|
||||||
|
common.MuxPack.Put(pack)
|
||||||
|
logs.Error("mux: new pack err", err)
|
||||||
|
s.Close()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
s.writeQueue.Push(pack)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Mux) writeSession() {
|
||||||
|
go s.packBuf()
|
||||||
|
//go s.writeBuf()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Mux) packBuf() {
|
||||||
|
//buffer := common.BuffPool.Get()
|
||||||
|
for {
|
||||||
|
if s.IsClose {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
//buffer.Reset()
|
||||||
|
pack := s.writeQueue.Pop()
|
||||||
|
if s.IsClose {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
//buffer := common.BuffPool.Get()
|
||||||
|
err := pack.Pack(s.conn)
|
||||||
|
common.MuxPack.Put(pack)
|
||||||
|
if err != nil {
|
||||||
|
logs.Error("mux: pack err", err)
|
||||||
|
//common.BuffPool.Put(buffer)
|
||||||
|
s.Close()
|
||||||
|
break
|
||||||
|
}
|
||||||
|
//logs.Warn(buffer.String())
|
||||||
|
//s.bufQueue.Push(buffer)
|
||||||
|
//l := buffer.Len()
|
||||||
|
//n, err := buffer.WriteTo(s.conn)
|
||||||
|
//common.BuffPool.Put(buffer)
|
||||||
|
//if err != nil || int(n) != l {
|
||||||
|
// logs.Error("mux: close from write session fail ", err, n, l)
|
||||||
|
// s.Close()
|
||||||
|
// break
|
||||||
|
//}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//func (s *Mux) writeBuf() {
|
||||||
|
// for {
|
||||||
|
// if s.IsClose {
|
||||||
|
// break
|
||||||
|
// }
|
||||||
|
// buffer, err := s.bufQueue.Pop()
|
||||||
|
// if err != nil {
|
||||||
|
// break
|
||||||
|
// }
|
||||||
|
// l := buffer.Len()
|
||||||
|
// n, err := buffer.WriteTo(s.conn)
|
||||||
|
// common.BuffPool.Put(buffer)
|
||||||
|
// if err != nil || int(n) != l {
|
||||||
|
// logs.Warn("close from write session fail ", err, n, l)
|
||||||
|
// s.Close()
|
||||||
|
// break
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
|
||||||
|
func (s *Mux) ping() {
|
||||||
|
go func() {
|
||||||
|
now, _ := time.Now().UTC().MarshalText()
|
||||||
|
s.sendInfo(common.MUX_PING_FLAG, common.MUX_PING, now)
|
||||||
|
// send the ping flag and get the latency first
|
||||||
|
ticker := time.NewTicker(time.Second * 5)
|
||||||
|
for {
|
||||||
|
if s.IsClose {
|
||||||
|
ticker.Stop()
|
||||||
|
break
|
||||||
|
}
|
||||||
|
select {
|
||||||
|
case <-ticker.C:
|
||||||
|
}
|
||||||
|
if atomic.LoadUint32(&s.pingCheckTime) >= 60 {
|
||||||
|
logs.Error("mux: ping time out")
|
||||||
|
s.Close()
|
||||||
|
// more than 5 minutes not receive the ping return package,
|
||||||
|
// mux conn is damaged, maybe a packet drop, close it
|
||||||
|
break
|
||||||
|
}
|
||||||
|
now, _ := time.Now().UTC().MarshalText()
|
||||||
|
s.sendInfo(common.MUX_PING_FLAG, common.MUX_PING, now)
|
||||||
|
atomic.AddUint32(&s.pingCheckTime, 1)
|
||||||
|
if atomic.LoadUint32(&s.pingOk) > 10 && s.connType == "kcp" {
|
||||||
|
logs.Error("mux: kcp ping err")
|
||||||
|
s.Close()
|
||||||
|
break
|
||||||
|
}
|
||||||
|
atomic.AddUint32(&s.pingOk, 1)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Mux) pingReturn() {
|
||||||
|
go func() {
|
||||||
|
var now time.Time
|
||||||
|
var data []byte
|
||||||
|
for {
|
||||||
|
if s.IsClose {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
select {
|
||||||
|
case data = <-s.pingCh:
|
||||||
|
atomic.StoreUint32(&s.pingCheckTime, 0)
|
||||||
|
case <-s.closeChan:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
_ = now.UnmarshalText(data)
|
||||||
|
latency := time.Now().UTC().Sub(now).Seconds() / 2
|
||||||
|
if latency > 0 {
|
||||||
|
atomic.StoreUint64(&s.latency, math.Float64bits(s.counter.Latency(latency)))
|
||||||
|
// convert float64 to bits, store it atomic
|
||||||
|
}
|
||||||
|
//logs.Warn("latency", math.Float64frombits(atomic.LoadUint64(&s.latency)))
|
||||||
|
if cap(data) > 0 {
|
||||||
|
common.WindowBuff.Put(data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Mux) readSession() {
|
||||||
|
go func() {
|
||||||
|
var connection *conn
|
||||||
|
for {
|
||||||
|
if s.IsClose {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
connection = s.newConnQueue.Pop()
|
||||||
|
if s.IsClose {
|
||||||
|
break // make sure that is closed
|
||||||
|
}
|
||||||
|
s.connMap.Set(connection.connId, connection) //it has been set before send ok
|
||||||
|
s.newConnCh <- connection
|
||||||
|
s.sendInfo(common.MUX_NEW_CONN_OK, connection.connId, nil)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
go func() {
|
||||||
|
pack := common.MuxPack.Get()
|
||||||
|
var l uint16
|
||||||
|
var err error
|
||||||
|
for {
|
||||||
|
if s.IsClose {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
pack = common.MuxPack.Get()
|
||||||
|
s.bw.StartRead()
|
||||||
|
if l, err = pack.UnPack(s.conn); err != nil {
|
||||||
|
logs.Error("mux: read session unpack from connection err", err)
|
||||||
|
s.Close()
|
||||||
|
break
|
||||||
|
}
|
||||||
|
s.bw.SetCopySize(l)
|
||||||
|
atomic.StoreUint32(&s.pingOk, 0)
|
||||||
|
switch pack.Flag {
|
||||||
|
case common.MUX_NEW_CONN: //new connection
|
||||||
|
connection := NewConn(pack.Id, s)
|
||||||
|
s.newConnQueue.Push(connection)
|
||||||
|
continue
|
||||||
|
case common.MUX_PING_FLAG: //ping
|
||||||
|
s.sendInfo(common.MUX_PING_RETURN, common.MUX_PING, pack.Content)
|
||||||
|
common.WindowBuff.Put(pack.Content)
|
||||||
|
continue
|
||||||
|
case common.MUX_PING_RETURN:
|
||||||
|
//go func(content []byte) {
|
||||||
|
s.pingCh <- pack.Content
|
||||||
|
//}(pack.Content)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if connection, ok := s.connMap.Get(pack.Id); ok && !connection.isClose {
|
||||||
|
switch pack.Flag {
|
||||||
|
case common.MUX_NEW_MSG, common.MUX_NEW_MSG_PART: //new msg from remote connection
|
||||||
|
err = s.newMsg(connection, pack)
|
||||||
|
if err != nil {
|
||||||
|
logs.Error("mux: read session connection new msg err", err)
|
||||||
|
connection.Close()
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
case common.MUX_NEW_CONN_OK: //connection ok
|
||||||
|
connection.connStatusOkCh <- struct{}{}
|
||||||
|
continue
|
||||||
|
case common.MUX_NEW_CONN_Fail:
|
||||||
|
connection.connStatusFailCh <- struct{}{}
|
||||||
|
continue
|
||||||
|
case common.MUX_MSG_SEND_OK:
|
||||||
|
if connection.isClose {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
connection.sendWindow.SetSize(pack.Window, pack.ReadLength)
|
||||||
|
continue
|
||||||
|
case common.MUX_CONN_CLOSE: //close the connection
|
||||||
|
connection.closeFlag = true
|
||||||
|
//s.connMap.Delete(pack.Id)
|
||||||
|
//go func(connection *conn) {
|
||||||
|
connection.receiveWindow.Stop() // close signal to receive window
|
||||||
|
//}(connection)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
} else if pack.Flag == common.MUX_CONN_CLOSE {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
common.MuxPack.Put(pack)
|
||||||
|
}
|
||||||
|
common.MuxPack.Put(pack)
|
||||||
|
s.Close()
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Mux) newMsg(connection *conn, pack *common.MuxPackager) (err error) {
|
||||||
|
if connection.isClose {
|
||||||
|
err = io.ErrClosedPipe
|
||||||
|
return
|
||||||
|
}
|
||||||
|
//logs.Warn("read session receive new msg", pack.Length)
|
||||||
|
//go func(connection *conn, pack *common.MuxPackager) { // do not block read session
|
||||||
|
//insert into queue
|
||||||
|
if pack.Flag == common.MUX_NEW_MSG_PART {
|
||||||
|
err = connection.receiveWindow.Write(pack.Content, pack.Length, true, pack.Id)
|
||||||
|
}
|
||||||
|
if pack.Flag == common.MUX_NEW_MSG {
|
||||||
|
err = connection.receiveWindow.Write(pack.Content, pack.Length, false, pack.Id)
|
||||||
|
}
|
||||||
|
//logs.Warn("read session write success", pack.Length)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Mux) Close() (err error) {
|
||||||
|
logs.Warn("close mux")
|
||||||
|
if s.IsClose {
|
||||||
|
return errors.New("the mux has closed")
|
||||||
|
}
|
||||||
|
s.IsClose = true
|
||||||
|
s.connMap.Close()
|
||||||
|
s.connMap = nil
|
||||||
|
//s.bufQueue.Stop()
|
||||||
|
s.closeChan <- struct{}{}
|
||||||
|
close(s.newConnCh)
|
||||||
|
err = s.conn.Close()
|
||||||
|
s.release()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Mux) release() {
|
||||||
|
for {
|
||||||
|
pack := s.writeQueue.TryPop()
|
||||||
|
if pack == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if pack.BasePackager.Content != nil {
|
||||||
|
common.WindowBuff.Put(pack.BasePackager.Content)
|
||||||
|
}
|
||||||
|
common.MuxPack.Put(pack)
|
||||||
|
}
|
||||||
|
for {
|
||||||
|
connection := s.newConnQueue.TryPop()
|
||||||
|
if connection == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
connection = nil
|
||||||
|
}
|
||||||
|
s.writeQueue.Stop()
|
||||||
|
s.newConnQueue.Stop()
|
||||||
|
}
|
||||||
|
|
||||||
|
//get new connId as unique flag
|
||||||
|
func (s *Mux) getId() (id int32) {
|
||||||
|
//Avoid going beyond the scope
|
||||||
|
if (math.MaxInt32 - s.id) < 10000 {
|
||||||
|
atomic.StoreInt32(&s.id, 0)
|
||||||
|
}
|
||||||
|
id = atomic.AddInt32(&s.id, 1)
|
||||||
|
if _, ok := s.connMap.Get(id); ok {
|
||||||
|
return s.getId()
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
type bandwidth struct {
|
||||||
|
readBandwidth uint64 // store in bits, but it's float64
|
||||||
|
readStart time.Time
|
||||||
|
lastReadStart time.Time
|
||||||
|
bufLength uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
func (Self *bandwidth) StartRead() {
|
||||||
|
if Self.readStart.IsZero() {
|
||||||
|
Self.readStart = time.Now()
|
||||||
|
}
|
||||||
|
if Self.bufLength >= common.MAXIMUM_SEGMENT_SIZE*300 {
|
||||||
|
Self.lastReadStart, Self.readStart = Self.readStart, time.Now()
|
||||||
|
Self.calcBandWidth()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (Self *bandwidth) SetCopySize(n uint16) {
|
||||||
|
Self.bufLength += uint32(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (Self *bandwidth) calcBandWidth() {
|
||||||
|
t := Self.readStart.Sub(Self.lastReadStart)
|
||||||
|
atomic.StoreUint64(&Self.readBandwidth, math.Float64bits(float64(Self.bufLength)/t.Seconds()))
|
||||||
|
Self.bufLength = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (Self *bandwidth) Get() (bw float64) {
|
||||||
|
// The zero value, 0 for numeric types
|
||||||
|
bw = math.Float64frombits(atomic.LoadUint64(&Self.readBandwidth))
|
||||||
|
if bw <= 0 {
|
||||||
|
bw = 100
|
||||||
|
}
|
||||||
|
//logs.Warn(bw)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const counterBits = 4
|
||||||
|
const counterMask = 1<<counterBits - 1
|
||||||
|
|
||||||
|
func newLatencyCounter() *latencyCounter {
|
||||||
|
return &latencyCounter{
|
||||||
|
buf: make([]float64, 1<<counterBits, 1<<counterBits),
|
||||||
|
headMin: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type latencyCounter struct {
|
||||||
|
buf []float64 //buf is a fixed length ring buffer,
|
||||||
|
// if buffer is full, new value will replace the oldest one.
|
||||||
|
headMin uint8 //head indicate the head in ring buffer,
|
||||||
|
// in meaning, slot in list will be replaced;
|
||||||
|
// min indicate this slot value is minimal in list.
|
||||||
|
}
|
||||||
|
|
||||||
|
func (Self *latencyCounter) unpack(idxs uint8) (head, min uint8) {
|
||||||
|
head = uint8((idxs >> counterBits) & counterMask)
|
||||||
|
// we set head is 4 bits
|
||||||
|
min = uint8(idxs & counterMask)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (Self *latencyCounter) pack(head, min uint8) uint8 {
|
||||||
|
return uint8(head<<counterBits) |
|
||||||
|
uint8(min&counterMask)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (Self *latencyCounter) add(value float64) {
|
||||||
|
head, min := Self.unpack(Self.headMin)
|
||||||
|
Self.buf[head] = value
|
||||||
|
if head == min {
|
||||||
|
min = Self.minimal()
|
||||||
|
//if head equals min, means the min slot already be replaced,
|
||||||
|
// so we need to find another minimal value in the list,
|
||||||
|
// and change the min indicator
|
||||||
|
}
|
||||||
|
if Self.buf[min] > value {
|
||||||
|
min = head
|
||||||
|
}
|
||||||
|
head++
|
||||||
|
Self.headMin = Self.pack(head, min)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (Self *latencyCounter) minimal() (min uint8) {
|
||||||
|
var val float64
|
||||||
|
var i uint8
|
||||||
|
for i = 0; i < counterMask; i++ {
|
||||||
|
if Self.buf[i] > 0 {
|
||||||
|
if val > Self.buf[i] {
|
||||||
|
val = Self.buf[i]
|
||||||
|
min = i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (Self *latencyCounter) Latency(value float64) (latency float64) {
|
||||||
|
Self.add(value)
|
||||||
|
_, min := Self.unpack(Self.headMin)
|
||||||
|
latency = Self.buf[min] * Self.countSuccess()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const lossRatio = 1.6
|
||||||
|
|
||||||
|
func (Self *latencyCounter) countSuccess() (successRate float64) {
|
||||||
|
var success, loss, i uint8
|
||||||
|
_, min := Self.unpack(Self.headMin)
|
||||||
|
for i = 0; i < counterMask; i++ {
|
||||||
|
if Self.buf[i] > lossRatio*Self.buf[min] && Self.buf[i] > 0 {
|
||||||
|
loss++
|
||||||
|
}
|
||||||
|
if Self.buf[i] <= lossRatio*Self.buf[min] && Self.buf[i] > 0 {
|
||||||
|
success++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// counting all the data in the ring buf, except zero
|
||||||
|
successRate = float64(success) / float64(loss+success)
|
||||||
|
return
|
||||||
|
}
|
447
lib/mux/mux_test.go
Normal file
447
lib/mux/mux_test.go
Normal file
@ -0,0 +1,447 @@
|
|||||||
|
package mux
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"fmt"
|
||||||
|
"github.com/cnlh/nps/lib/common"
|
||||||
|
"github.com/cnlh/nps/lib/goroutine"
|
||||||
|
"io"
|
||||||
|
"log"
|
||||||
|
"net"
|
||||||
|
"net/http"
|
||||||
|
"net/http/httputil"
|
||||||
|
_ "net/http/pprof"
|
||||||
|
"strconv"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
"github.com/astaxie/beego/logs"
|
||||||
|
)
|
||||||
|
|
||||||
|
var conn1 net.Conn
|
||||||
|
var conn2 net.Conn
|
||||||
|
|
||||||
|
func TestNewMux(t *testing.T) {
|
||||||
|
go func() {
|
||||||
|
http.ListenAndServe("0.0.0.0:8889", nil)
|
||||||
|
}()
|
||||||
|
logs.EnableFuncCallDepth(true)
|
||||||
|
logs.SetLogFuncCallDepth(3)
|
||||||
|
server()
|
||||||
|
client()
|
||||||
|
//poolConnCopy, _ := ants.NewPoolWithFunc(200000, common.copyConn, ants.WithNonblocking(false))
|
||||||
|
time.Sleep(time.Second * 3)
|
||||||
|
go func() {
|
||||||
|
m2 := NewMux(conn2, "tcp")
|
||||||
|
for {
|
||||||
|
//logs.Warn("npc starting accept")
|
||||||
|
c, err := m2.Accept()
|
||||||
|
if err != nil {
|
||||||
|
logs.Warn(err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
//logs.Warn("npc accept success ")
|
||||||
|
c2, err := net.Dial("tcp", "127.0.0.1:80")
|
||||||
|
if err != nil {
|
||||||
|
logs.Warn(err)
|
||||||
|
c.Close()
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
//c2.(*net.TCPConn).SetReadBuffer(0)
|
||||||
|
//c2.(*net.TCPConn).SetReadBuffer(0)
|
||||||
|
_ = goroutine.CopyConnsPool.Invoke(goroutine.NewConns(c, c2, nil))
|
||||||
|
//go func(c2 net.Conn, c *conn) {
|
||||||
|
// wg := new(sync.WaitGroup)
|
||||||
|
// wg.Add(2)
|
||||||
|
// _ = poolConnCopy.Invoke(common.newConnGroup(c2, c, wg))
|
||||||
|
// //go func() {
|
||||||
|
// // _, err = common.CopyBuffer(c2, c)
|
||||||
|
// // if err != nil {
|
||||||
|
// // c2.Close()
|
||||||
|
// // c.Close()
|
||||||
|
// // //logs.Warn("close npc by copy from nps", err, c.connId)
|
||||||
|
// // }
|
||||||
|
// // wg.Done()
|
||||||
|
// //}()
|
||||||
|
// //wg.Add(1)
|
||||||
|
// _ = poolConnCopy.Invoke(common.newConnGroup(c, c2, wg))
|
||||||
|
// //go func() {
|
||||||
|
// // _, err = common.CopyBuffer(c, c2)
|
||||||
|
// // if err != nil {
|
||||||
|
// // c2.Close()
|
||||||
|
// // c.Close()
|
||||||
|
// // //logs.Warn("close npc by copy from server", err, c.connId)
|
||||||
|
// // }
|
||||||
|
// // wg.Done()
|
||||||
|
// //}()
|
||||||
|
// //logs.Warn("npc wait")
|
||||||
|
// wg.Wait()
|
||||||
|
//}(c2, c.(*conn))
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
m1 := NewMux(conn1, "tcp")
|
||||||
|
l, err := net.Listen("tcp", "127.0.0.1:7777")
|
||||||
|
if err != nil {
|
||||||
|
logs.Warn(err)
|
||||||
|
}
|
||||||
|
for {
|
||||||
|
//logs.Warn("nps starting accept")
|
||||||
|
conns, err := l.Accept()
|
||||||
|
if err != nil {
|
||||||
|
logs.Warn(err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
//conns.(*net.TCPConn).SetReadBuffer(0)
|
||||||
|
//conns.(*net.TCPConn).SetReadBuffer(0)
|
||||||
|
//logs.Warn("nps accept success starting new conn")
|
||||||
|
tmpCpnn, err := m1.NewConn()
|
||||||
|
if err != nil {
|
||||||
|
logs.Warn("nps new conn err ", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
//logs.Warn("nps new conn success ", tmpCpnn.connId)
|
||||||
|
_ = goroutine.CopyConnsPool.Invoke(goroutine.NewConns(tmpCpnn, conns, nil))
|
||||||
|
//go func(tmpCpnn *conn, conns net.Conn) {
|
||||||
|
// wg := new(sync.WaitGroup)
|
||||||
|
// wg.Add(2)
|
||||||
|
// _ = poolConnCopy.Invoke(common.newConnGroup(tmpCpnn, conns, wg))
|
||||||
|
// //go func() {
|
||||||
|
// // _, err := common.CopyBuffer(tmpCpnn, conns)
|
||||||
|
// // if err != nil {
|
||||||
|
// // conns.Close()
|
||||||
|
// // tmpCpnn.Close()
|
||||||
|
// // //logs.Warn("close nps by copy from user", tmpCpnn.connId, err)
|
||||||
|
// // }
|
||||||
|
// //}()
|
||||||
|
// //wg.Add(1)
|
||||||
|
// _ = poolConnCopy.Invoke(common.newConnGroup(conns, tmpCpnn, wg))
|
||||||
|
// //time.Sleep(time.Second)
|
||||||
|
// //_, err = common.CopyBuffer(conns, tmpCpnn)
|
||||||
|
// //if err != nil {
|
||||||
|
// // conns.Close()
|
||||||
|
// // tmpCpnn.Close()
|
||||||
|
// // //logs.Warn("close nps by copy from npc ", tmpCpnn.connId, err)
|
||||||
|
// //}
|
||||||
|
// wg.Wait()
|
||||||
|
//}(tmpCpnn, conns)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
//go NewLogServer()
|
||||||
|
time.Sleep(time.Second * 5)
|
||||||
|
//for i := 0; i < 1; i++ {
|
||||||
|
// go test_raw(i)
|
||||||
|
//}
|
||||||
|
//test_request()
|
||||||
|
|
||||||
|
for {
|
||||||
|
time.Sleep(time.Second * 5)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func server() {
|
||||||
|
var err error
|
||||||
|
l, err := net.Listen("tcp", "127.0.0.1:9999")
|
||||||
|
if err != nil {
|
||||||
|
logs.Warn(err)
|
||||||
|
}
|
||||||
|
go func() {
|
||||||
|
conn1, err = l.Accept()
|
||||||
|
if err != nil {
|
||||||
|
logs.Warn(err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func client() {
|
||||||
|
var err error
|
||||||
|
conn2, err = net.Dial("tcp", "127.0.0.1:9999")
|
||||||
|
if err != nil {
|
||||||
|
logs.Warn(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func test_request() {
|
||||||
|
conn, _ := net.Dial("tcp", "127.0.0.1:7777")
|
||||||
|
for i := 0; i < 1000; i++ {
|
||||||
|
conn.Write([]byte(`GET / HTTP/1.1
|
||||||
|
Host: 127.0.0.1:7777
|
||||||
|
Connection: keep-alive
|
||||||
|
|
||||||
|
|
||||||
|
`))
|
||||||
|
r, err := http.ReadResponse(bufio.NewReader(conn), nil)
|
||||||
|
if err != nil {
|
||||||
|
logs.Warn("close by read response err", err)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
logs.Warn("read response success", r)
|
||||||
|
b, err := httputil.DumpResponse(r, true)
|
||||||
|
if err != nil {
|
||||||
|
logs.Warn("close by dump response err", err)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
fmt.Println(string(b[:20]), err)
|
||||||
|
//time.Sleep(time.Second)
|
||||||
|
}
|
||||||
|
logs.Warn("finish")
|
||||||
|
}
|
||||||
|
|
||||||
|
func test_raw(k int) {
|
||||||
|
for i := 0; i < 1000; i++ {
|
||||||
|
ti := time.Now()
|
||||||
|
conn, err := net.Dial("tcp", "127.0.0.1:7777")
|
||||||
|
if err != nil {
|
||||||
|
logs.Warn("conn dial err", err)
|
||||||
|
}
|
||||||
|
tid := time.Now()
|
||||||
|
conn.Write([]byte(`GET /videojs5/video.js HTTP/1.1
|
||||||
|
Host: 127.0.0.1:7777
|
||||||
|
|
||||||
|
|
||||||
|
`))
|
||||||
|
tiw := time.Now()
|
||||||
|
buf := make([]byte, 3572)
|
||||||
|
n, err := io.ReadFull(conn, buf)
|
||||||
|
//n, err := conn.Read(buf)
|
||||||
|
if err != nil {
|
||||||
|
logs.Warn("close by read response err", err)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
logs.Warn(n, string(buf[:50]), "\n--------------\n", string(buf[n-50:n]))
|
||||||
|
//time.Sleep(time.Second)
|
||||||
|
err = conn.Close()
|
||||||
|
if err != nil {
|
||||||
|
logs.Warn("close conn err ", err)
|
||||||
|
}
|
||||||
|
now := time.Now()
|
||||||
|
du := now.Sub(ti).Seconds()
|
||||||
|
dud := now.Sub(tid).Seconds()
|
||||||
|
duw := now.Sub(tiw).Seconds()
|
||||||
|
if du > 1 {
|
||||||
|
logs.Warn("duration long", du, dud, duw, k, i)
|
||||||
|
}
|
||||||
|
if n != 3572 {
|
||||||
|
logs.Warn("n loss", n, string(buf))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
logs.Warn("finish")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNewConn(t *testing.T) {
|
||||||
|
buf := common.GetBufPoolCopy()
|
||||||
|
logs.Warn(len(buf), cap(buf))
|
||||||
|
//b := pool.GetBufPoolCopy()
|
||||||
|
//b[0] = 1
|
||||||
|
//b[1] = 2
|
||||||
|
//b[2] = 3
|
||||||
|
b := []byte{1, 2, 3}
|
||||||
|
logs.Warn(copy(buf[:3], b), len(buf), cap(buf))
|
||||||
|
logs.Warn(len(buf), buf[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDQueue(t *testing.T) {
|
||||||
|
logs.EnableFuncCallDepth(true)
|
||||||
|
logs.SetLogFuncCallDepth(3)
|
||||||
|
d := new(bufDequeue)
|
||||||
|
d.vals = make([]unsafe.Pointer, 8)
|
||||||
|
go func() {
|
||||||
|
time.Sleep(time.Second)
|
||||||
|
for i := 0; i < 10; i++ {
|
||||||
|
logs.Warn(i)
|
||||||
|
logs.Warn(d.popTail())
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
go func() {
|
||||||
|
time.Sleep(time.Second)
|
||||||
|
for i := 0; i < 10; i++ {
|
||||||
|
data := "test"
|
||||||
|
go logs.Warn(i, unsafe.Pointer(&data), d.pushHead(unsafe.Pointer(&data)))
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
time.Sleep(time.Second * 3)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestChain(t *testing.T) {
|
||||||
|
go func() {
|
||||||
|
log.Println(http.ListenAndServe("0.0.0.0:8889", nil))
|
||||||
|
}()
|
||||||
|
logs.EnableFuncCallDepth(true)
|
||||||
|
logs.SetLogFuncCallDepth(3)
|
||||||
|
time.Sleep(time.Second * 5)
|
||||||
|
d := new(bufChain)
|
||||||
|
d.new(256)
|
||||||
|
go func() {
|
||||||
|
time.Sleep(time.Second)
|
||||||
|
for i := 0; i < 30000; i++ {
|
||||||
|
unsa, ok := d.popTail()
|
||||||
|
str := (*string)(unsa)
|
||||||
|
if ok {
|
||||||
|
fmt.Println(i, str, *str, ok)
|
||||||
|
//logs.Warn(i, str, *str, ok)
|
||||||
|
} else {
|
||||||
|
fmt.Println("nil", i, ok)
|
||||||
|
//logs.Warn("nil", i, ok)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
go func() {
|
||||||
|
time.Sleep(time.Second)
|
||||||
|
for i := 0; i < 3000; i++ {
|
||||||
|
go func(i int) {
|
||||||
|
for n := 0; n < 10; n++ {
|
||||||
|
data := "test " + strconv.Itoa(i) + strconv.Itoa(n)
|
||||||
|
fmt.Println(data, unsafe.Pointer(&data))
|
||||||
|
//logs.Warn(data, unsafe.Pointer(&data))
|
||||||
|
d.pushHead(unsafe.Pointer(&data))
|
||||||
|
}
|
||||||
|
}(i)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
time.Sleep(time.Second * 100000)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFIFO(t *testing.T) {
|
||||||
|
go func() {
|
||||||
|
log.Println(http.ListenAndServe("0.0.0.0:8889", nil))
|
||||||
|
}()
|
||||||
|
logs.EnableFuncCallDepth(true)
|
||||||
|
logs.SetLogFuncCallDepth(3)
|
||||||
|
time.Sleep(time.Second * 5)
|
||||||
|
d := new(ReceiveWindowQueue)
|
||||||
|
d.New()
|
||||||
|
go func() {
|
||||||
|
time.Sleep(time.Second)
|
||||||
|
for i := 0; i < 1001; i++ {
|
||||||
|
data, err := d.Pop()
|
||||||
|
if err == nil {
|
||||||
|
//fmt.Println(i, string(data.buf), err)
|
||||||
|
logs.Warn(i, string(data.Buf), err)
|
||||||
|
common.ListElementPool.Put(data)
|
||||||
|
} else {
|
||||||
|
//fmt.Println("err", err)
|
||||||
|
logs.Warn("err", err)
|
||||||
|
}
|
||||||
|
//logs.Warn(d.Len())
|
||||||
|
}
|
||||||
|
logs.Warn("pop finish")
|
||||||
|
}()
|
||||||
|
go func() {
|
||||||
|
time.Sleep(time.Second * 10)
|
||||||
|
for i := 0; i < 1000; i++ {
|
||||||
|
by := []byte("test " + strconv.Itoa(i) + " ") //
|
||||||
|
data, _ := NewListElement(by, uint16(len(by)), true)
|
||||||
|
//fmt.Println(string((*data).buf), data)
|
||||||
|
//logs.Warn(string((*data).buf), data)
|
||||||
|
d.Push(data)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
time.Sleep(time.Second * 100000)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPriority(t *testing.T) {
|
||||||
|
go func() {
|
||||||
|
log.Println(http.ListenAndServe("0.0.0.0:8889", nil))
|
||||||
|
}()
|
||||||
|
logs.EnableFuncCallDepth(true)
|
||||||
|
logs.SetLogFuncCallDepth(3)
|
||||||
|
time.Sleep(time.Second * 5)
|
||||||
|
d := new(PriorityQueue)
|
||||||
|
d.New()
|
||||||
|
go func() {
|
||||||
|
time.Sleep(time.Second)
|
||||||
|
for i := 0; i < 360050; i++ {
|
||||||
|
data := d.Pop()
|
||||||
|
//fmt.Println(i, string(data.buf), err)
|
||||||
|
logs.Warn(i, string(data.Content), data)
|
||||||
|
}
|
||||||
|
logs.Warn("pop finish")
|
||||||
|
}()
|
||||||
|
go func() {
|
||||||
|
time.Sleep(time.Second * 10)
|
||||||
|
for i := 0; i < 30000; i++ {
|
||||||
|
go func(i int) {
|
||||||
|
for n := 0; n < 10; n++ {
|
||||||
|
data := new(common.MuxPackager)
|
||||||
|
by := []byte("test " + strconv.Itoa(i) + strconv.Itoa(n))
|
||||||
|
_ = data.NewPac(common.MUX_NEW_MSG_PART, int32(i), by)
|
||||||
|
//fmt.Println(string((*data).buf), data)
|
||||||
|
logs.Warn(string((*data).Content), data)
|
||||||
|
d.Push(data)
|
||||||
|
}
|
||||||
|
}(i)
|
||||||
|
go func(i int) {
|
||||||
|
data := new(common.MuxPackager)
|
||||||
|
_ = data.NewPac(common.MUX_NEW_CONN, int32(i), nil)
|
||||||
|
//fmt.Println(string((*data).buf), data)
|
||||||
|
logs.Warn(data)
|
||||||
|
d.Push(data)
|
||||||
|
}(i)
|
||||||
|
go func(i int) {
|
||||||
|
data := new(common.MuxPackager)
|
||||||
|
_ = data.NewPac(common.MUX_NEW_CONN_OK, int32(i), nil)
|
||||||
|
//fmt.Println(string((*data).buf), data)
|
||||||
|
logs.Warn(data)
|
||||||
|
d.Push(data)
|
||||||
|
}(i)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
time.Sleep(time.Second * 100000)
|
||||||
|
}
|
||||||
|
|
||||||
|
//func TestReceive(t *testing.T) {
|
||||||
|
// go func() {
|
||||||
|
// log.Println(http.ListenAndServe("0.0.0.0:8889", nil))
|
||||||
|
// }()
|
||||||
|
// logs.EnableFuncCallDepth(true)
|
||||||
|
// logs.SetLogFuncCallDepth(3)
|
||||||
|
// time.Sleep(time.Second * 5)
|
||||||
|
// mux := new(Mux)
|
||||||
|
// mux.bw.readBandwidth = float64(1*1024*1024)
|
||||||
|
// mux.latency = float64(1/1000)
|
||||||
|
// wind := new(ReceiveWindow)
|
||||||
|
// wind.New(mux)
|
||||||
|
// wind.
|
||||||
|
// go func() {
|
||||||
|
// time.Sleep(time.Second)
|
||||||
|
// for i := 0; i < 36000; i++ {
|
||||||
|
// data := d.Pop()
|
||||||
|
// //fmt.Println(i, string(data.buf), err)
|
||||||
|
// logs.Warn(i, string(data.Content), data)
|
||||||
|
// }
|
||||||
|
// }()
|
||||||
|
// go func() {
|
||||||
|
// time.Sleep(time.Second*10)
|
||||||
|
// for i := 0; i < 3000; i++ {
|
||||||
|
// go func(i int) {
|
||||||
|
// for n := 0; n < 10; n++{
|
||||||
|
// data := new(common.MuxPackager)
|
||||||
|
// by := []byte("test " + strconv.Itoa(i) + strconv.Itoa(n))
|
||||||
|
// _ = data.NewPac(common.MUX_NEW_MSG_PART, int32(i), by)
|
||||||
|
// //fmt.Println(string((*data).buf), data)
|
||||||
|
// logs.Warn(string((*data).Content), data)
|
||||||
|
// d.Push(data)
|
||||||
|
// }
|
||||||
|
// }(i)
|
||||||
|
// go func(i int) {
|
||||||
|
// data := new(common.MuxPackager)
|
||||||
|
// _ = data.NewPac(common.MUX_NEW_CONN, int32(i), nil)
|
||||||
|
// //fmt.Println(string((*data).buf), data)
|
||||||
|
// logs.Warn(data)
|
||||||
|
// d.Push(data)
|
||||||
|
// }(i)
|
||||||
|
// go func(i int) {
|
||||||
|
// data := new(common.MuxPackager)
|
||||||
|
// _ = data.NewPac(common.MUX_NEW_CONN_OK, int32(i), nil)
|
||||||
|
// //fmt.Println(string((*data).buf), data)
|
||||||
|
// logs.Warn(data)
|
||||||
|
// d.Push(data)
|
||||||
|
// }(i)
|
||||||
|
// }
|
||||||
|
// }()
|
||||||
|
// time.Sleep(time.Second * 100000)
|
||||||
|
//}
|
@ -1,4 +1,4 @@
|
|||||||
package pmux
|
package mux
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net"
|
"net"
|
||||||
@ -6,17 +6,15 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type PortConn struct {
|
type PortConn struct {
|
||||||
Conn net.Conn
|
Conn net.Conn
|
||||||
rs []byte
|
rs []byte
|
||||||
readMore bool
|
start int
|
||||||
start int
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func newPortConn(conn net.Conn, rs []byte, readMore bool) *PortConn {
|
func newPortConn(conn net.Conn, rs []byte) *PortConn {
|
||||||
return &PortConn{
|
return &PortConn{
|
||||||
Conn: conn,
|
Conn: conn,
|
||||||
rs: rs,
|
rs: rs,
|
||||||
readMore: readMore,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -31,15 +29,9 @@ func (pConn *PortConn) Read(b []byte) (n int, err error) {
|
|||||||
defer func() {
|
defer func() {
|
||||||
pConn.start = len(pConn.rs)
|
pConn.start = len(pConn.rs)
|
||||||
}()
|
}()
|
||||||
n = copy(b, pConn.rs[pConn.start:])
|
return copy(b, pConn.rs[pConn.start:]), nil
|
||||||
if !pConn.readMore {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
var n2 = 0
|
return pConn.Conn.Read(b)
|
||||||
n2, err = pConn.Conn.Read(b[n:])
|
|
||||||
n = n + n2
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pConn *PortConn) Write(b []byte) (n int, err error) {
|
func (pConn *PortConn) Write(b []byte) (n int, err error) {
|
@ -1,4 +1,4 @@
|
|||||||
package pmux
|
package mux
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
@ -1,6 +1,6 @@
|
|||||||
// This module is used for port reuse
|
// This module is used for port reuse
|
||||||
// Distinguish client, web manager , HTTP and HTTPS according to the difference of protocol
|
// Distinguish client, web manager , HTTP and HTTPS according to the difference of protocol
|
||||||
package pmux
|
package mux
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
@ -12,8 +12,8 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"ehang.io/nps/lib/common"
|
|
||||||
"github.com/astaxie/beego/logs"
|
"github.com/astaxie/beego/logs"
|
||||||
|
"github.com/cnlh/nps/lib/common"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -89,7 +89,6 @@ func (pMux *PortMux) process(conn net.Conn) {
|
|||||||
var ch chan *PortConn
|
var ch chan *PortConn
|
||||||
var rs []byte
|
var rs []byte
|
||||||
var buffer bytes.Buffer
|
var buffer bytes.Buffer
|
||||||
var readMore = false
|
|
||||||
switch common.BytesToNum(buf) {
|
switch common.BytesToNum(buf) {
|
||||||
case HTTP_CONNECT, HTTP_DELETE, HTTP_GET, HTTP_HEAD, HTTP_OPTIONS, HTTP_POST, HTTP_PUT, HTTP_TRACE: //http and manager
|
case HTTP_CONNECT, HTTP_DELETE, HTTP_GET, HTTP_HEAD, HTTP_OPTIONS, HTTP_POST, HTTP_PUT, HTTP_TRACE: //http and manager
|
||||||
buffer.Reset()
|
buffer.Reset()
|
||||||
@ -124,7 +123,6 @@ func (pMux *PortMux) process(conn net.Conn) {
|
|||||||
case CLIENT: // client connection
|
case CLIENT: // client connection
|
||||||
ch = pMux.clientConn
|
ch = pMux.clientConn
|
||||||
default: // https
|
default: // https
|
||||||
readMore = true
|
|
||||||
ch = pMux.httpsConn
|
ch = pMux.httpsConn
|
||||||
}
|
}
|
||||||
if len(rs) == 0 {
|
if len(rs) == 0 {
|
||||||
@ -133,13 +131,13 @@ func (pMux *PortMux) process(conn net.Conn) {
|
|||||||
timer := time.NewTimer(ACCEPT_TIME_OUT)
|
timer := time.NewTimer(ACCEPT_TIME_OUT)
|
||||||
select {
|
select {
|
||||||
case <-timer.C:
|
case <-timer.C:
|
||||||
case ch <- newPortConn(conn, rs, readMore):
|
case ch <- newPortConn(conn, rs):
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pMux *PortMux) Close() error {
|
func (pMux *PortMux) Close() error {
|
||||||
if pMux.isClose {
|
if pMux.isClose {
|
||||||
return errors.New("the port pmux has closed")
|
return errors.New("the port mux has closed")
|
||||||
}
|
}
|
||||||
pMux.isClose = true
|
pMux.isClose = true
|
||||||
close(pMux.clientConn)
|
close(pMux.clientConn)
|
@ -1,4 +1,4 @@
|
|||||||
package pmux
|
package mux
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
583
lib/mux/queue.go
Normal file
583
lib/mux/queue.go
Normal file
@ -0,0 +1,583 @@
|
|||||||
|
package mux
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"github.com/cnlh/nps/lib/common"
|
||||||
|
"io"
|
||||||
|
"math"
|
||||||
|
"runtime"
|
||||||
|
"sync"
|
||||||
|
"sync/atomic"
|
||||||
|
"time"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
type PriorityQueue struct {
|
||||||
|
highestChain *bufChain
|
||||||
|
middleChain *bufChain
|
||||||
|
lowestChain *bufChain
|
||||||
|
starving uint8
|
||||||
|
stop bool
|
||||||
|
cond *sync.Cond
|
||||||
|
}
|
||||||
|
|
||||||
|
func (Self *PriorityQueue) New() {
|
||||||
|
Self.highestChain = new(bufChain)
|
||||||
|
Self.highestChain.new(4)
|
||||||
|
Self.middleChain = new(bufChain)
|
||||||
|
Self.middleChain.new(32)
|
||||||
|
Self.lowestChain = new(bufChain)
|
||||||
|
Self.lowestChain.new(256)
|
||||||
|
locker := new(sync.Mutex)
|
||||||
|
Self.cond = sync.NewCond(locker)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (Self *PriorityQueue) Push(packager *common.MuxPackager) {
|
||||||
|
//logs.Warn("push start")
|
||||||
|
Self.push(packager)
|
||||||
|
Self.cond.Broadcast()
|
||||||
|
//logs.Warn("push finish")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (Self *PriorityQueue) push(packager *common.MuxPackager) {
|
||||||
|
switch packager.Flag {
|
||||||
|
case common.MUX_PING_FLAG, common.MUX_PING_RETURN:
|
||||||
|
Self.highestChain.pushHead(unsafe.Pointer(packager))
|
||||||
|
// the ping package need highest priority
|
||||||
|
// prevent ping calculation error
|
||||||
|
case common.MUX_NEW_CONN, common.MUX_NEW_CONN_OK, common.MUX_NEW_CONN_Fail:
|
||||||
|
// the new conn package need some priority too
|
||||||
|
Self.middleChain.pushHead(unsafe.Pointer(packager))
|
||||||
|
default:
|
||||||
|
Self.lowestChain.pushHead(unsafe.Pointer(packager))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const maxStarving uint8 = 8
|
||||||
|
|
||||||
|
func (Self *PriorityQueue) Pop() (packager *common.MuxPackager) {
|
||||||
|
var iter bool
|
||||||
|
for {
|
||||||
|
packager = Self.TryPop()
|
||||||
|
if packager != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if Self.stop {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if iter {
|
||||||
|
break
|
||||||
|
// trying to pop twice
|
||||||
|
}
|
||||||
|
iter = true
|
||||||
|
runtime.Gosched()
|
||||||
|
}
|
||||||
|
Self.cond.L.Lock()
|
||||||
|
defer Self.cond.L.Unlock()
|
||||||
|
for packager = Self.TryPop(); packager == nil; {
|
||||||
|
if Self.stop {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
//logs.Warn("queue into wait")
|
||||||
|
Self.cond.Wait()
|
||||||
|
// wait for it with no more iter
|
||||||
|
packager = Self.TryPop()
|
||||||
|
//logs.Warn("queue wait finish", packager)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (Self *PriorityQueue) TryPop() (packager *common.MuxPackager) {
|
||||||
|
ptr, ok := Self.highestChain.popTail()
|
||||||
|
if ok {
|
||||||
|
packager = (*common.MuxPackager)(ptr)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if Self.starving < maxStarving {
|
||||||
|
// not pop too much, lowestChain will wait too long
|
||||||
|
ptr, ok = Self.middleChain.popTail()
|
||||||
|
if ok {
|
||||||
|
packager = (*common.MuxPackager)(ptr)
|
||||||
|
Self.starving++
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ptr, ok = Self.lowestChain.popTail()
|
||||||
|
if ok {
|
||||||
|
packager = (*common.MuxPackager)(ptr)
|
||||||
|
if Self.starving > 0 {
|
||||||
|
Self.starving = uint8(Self.starving / 2)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if Self.starving > 0 {
|
||||||
|
ptr, ok = Self.middleChain.popTail()
|
||||||
|
if ok {
|
||||||
|
packager = (*common.MuxPackager)(ptr)
|
||||||
|
Self.starving++
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (Self *PriorityQueue) Stop() {
|
||||||
|
Self.stop = true
|
||||||
|
Self.cond.Broadcast()
|
||||||
|
}
|
||||||
|
|
||||||
|
type ConnQueue struct {
|
||||||
|
chain *bufChain
|
||||||
|
starving uint8
|
||||||
|
stop bool
|
||||||
|
cond *sync.Cond
|
||||||
|
}
|
||||||
|
|
||||||
|
func (Self *ConnQueue) New() {
|
||||||
|
Self.chain = new(bufChain)
|
||||||
|
Self.chain.new(32)
|
||||||
|
locker := new(sync.Mutex)
|
||||||
|
Self.cond = sync.NewCond(locker)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (Self *ConnQueue) Push(connection *conn) {
|
||||||
|
Self.chain.pushHead(unsafe.Pointer(connection))
|
||||||
|
Self.cond.Broadcast()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (Self *ConnQueue) Pop() (connection *conn) {
|
||||||
|
var iter bool
|
||||||
|
for {
|
||||||
|
connection = Self.TryPop()
|
||||||
|
if connection != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if Self.stop {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if iter {
|
||||||
|
break
|
||||||
|
// trying to pop twice
|
||||||
|
}
|
||||||
|
iter = true
|
||||||
|
runtime.Gosched()
|
||||||
|
}
|
||||||
|
Self.cond.L.Lock()
|
||||||
|
defer Self.cond.L.Unlock()
|
||||||
|
for connection = Self.TryPop(); connection == nil; {
|
||||||
|
if Self.stop {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
//logs.Warn("queue into wait")
|
||||||
|
Self.cond.Wait()
|
||||||
|
// wait for it with no more iter
|
||||||
|
connection = Self.TryPop()
|
||||||
|
//logs.Warn("queue wait finish", packager)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (Self *ConnQueue) TryPop() (connection *conn) {
|
||||||
|
ptr, ok := Self.chain.popTail()
|
||||||
|
if ok {
|
||||||
|
connection = (*conn)(ptr)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (Self *ConnQueue) Stop() {
|
||||||
|
Self.stop = true
|
||||||
|
Self.cond.Broadcast()
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewListElement(buf []byte, l uint16, part bool) (element *common.ListElement, err error) {
|
||||||
|
if uint16(len(buf)) != l {
|
||||||
|
err = errors.New("ListElement: buf length not match")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
//if l == 0 {
|
||||||
|
// logs.Warn("push zero")
|
||||||
|
//}
|
||||||
|
element = common.ListElementPool.Get()
|
||||||
|
element.Buf = buf
|
||||||
|
element.L = l
|
||||||
|
element.Part = part
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
type ReceiveWindowQueue struct {
|
||||||
|
chain *bufChain
|
||||||
|
stopOp chan struct{}
|
||||||
|
readOp chan struct{}
|
||||||
|
lengthWait uint64 // really strange ???? need put here
|
||||||
|
// https://golang.org/pkg/sync/atomic/#pkg-note-BUG
|
||||||
|
// On non-Linux ARM, the 64-bit functions use instructions unavailable before the ARMv6k core.
|
||||||
|
// On ARM, x86-32, and 32-bit MIPS, it is the caller's responsibility
|
||||||
|
// to arrange for 64-bit alignment of 64-bit words accessed atomically.
|
||||||
|
// The first word in a variable or in an allocated struct, array, or slice can be relied upon to be 64-bit aligned.
|
||||||
|
timeout time.Time
|
||||||
|
}
|
||||||
|
|
||||||
|
func (Self *ReceiveWindowQueue) New() {
|
||||||
|
Self.readOp = make(chan struct{})
|
||||||
|
Self.chain = new(bufChain)
|
||||||
|
Self.chain.new(64)
|
||||||
|
Self.stopOp = make(chan struct{}, 2)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (Self *ReceiveWindowQueue) Push(element *common.ListElement) {
|
||||||
|
var length, wait uint32
|
||||||
|
for {
|
||||||
|
ptrs := atomic.LoadUint64(&Self.lengthWait)
|
||||||
|
length, wait = Self.chain.head.unpack(ptrs)
|
||||||
|
length += uint32(element.L)
|
||||||
|
if atomic.CompareAndSwapUint64(&Self.lengthWait, ptrs, Self.chain.head.pack(length, 0)) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
// another goroutine change the length or into wait, make sure
|
||||||
|
}
|
||||||
|
//logs.Warn("window push before", Self.Len(), uint32(element.l), len(element.buf))
|
||||||
|
Self.chain.pushHead(unsafe.Pointer(element))
|
||||||
|
//logs.Warn("window push", Self.Len())
|
||||||
|
if wait == 1 {
|
||||||
|
Self.allowPop()
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (Self *ReceiveWindowQueue) Pop() (element *common.ListElement, err error) {
|
||||||
|
var length uint32
|
||||||
|
startPop:
|
||||||
|
ptrs := atomic.LoadUint64(&Self.lengthWait)
|
||||||
|
length, _ = Self.chain.head.unpack(ptrs)
|
||||||
|
if length == 0 {
|
||||||
|
if !atomic.CompareAndSwapUint64(&Self.lengthWait, ptrs, Self.chain.head.pack(0, 1)) {
|
||||||
|
goto startPop // another goroutine is pushing
|
||||||
|
}
|
||||||
|
err = Self.waitPush()
|
||||||
|
// there is no more data in queue, wait for it
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
goto startPop // wait finish, trying to get the new status
|
||||||
|
}
|
||||||
|
// length is not zero, so try to pop
|
||||||
|
for {
|
||||||
|
element = Self.TryPop()
|
||||||
|
if element != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
runtime.Gosched() // another goroutine is still pushing
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (Self *ReceiveWindowQueue) TryPop() (element *common.ListElement) {
|
||||||
|
ptr, ok := Self.chain.popTail()
|
||||||
|
if ok {
|
||||||
|
//logs.Warn("window pop before", Self.Len())
|
||||||
|
element = (*common.ListElement)(ptr)
|
||||||
|
atomic.AddUint64(&Self.lengthWait, ^(uint64(element.L)<<dequeueBits - 1))
|
||||||
|
//logs.Warn("window pop", Self.Len(), uint32(element.l))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (Self *ReceiveWindowQueue) allowPop() (closed bool) {
|
||||||
|
//logs.Warn("allow pop", Self.Len())
|
||||||
|
select {
|
||||||
|
case Self.readOp <- struct{}{}:
|
||||||
|
return false
|
||||||
|
case <-Self.stopOp:
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (Self *ReceiveWindowQueue) waitPush() (err error) {
|
||||||
|
//logs.Warn("wait push")
|
||||||
|
//defer logs.Warn("wait push finish")
|
||||||
|
t := Self.timeout.Sub(time.Now())
|
||||||
|
if t <= 0 {
|
||||||
|
t = time.Minute * 5
|
||||||
|
}
|
||||||
|
timer := time.NewTimer(t)
|
||||||
|
defer timer.Stop()
|
||||||
|
//logs.Warn("queue into wait")
|
||||||
|
select {
|
||||||
|
case <-Self.readOp:
|
||||||
|
//logs.Warn("queue wait finish")
|
||||||
|
return nil
|
||||||
|
case <-Self.stopOp:
|
||||||
|
err = io.EOF
|
||||||
|
return
|
||||||
|
case <-timer.C:
|
||||||
|
err = errors.New("mux.queue: read time out")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (Self *ReceiveWindowQueue) Len() (n uint32) {
|
||||||
|
ptrs := atomic.LoadUint64(&Self.lengthWait)
|
||||||
|
n, _ = Self.chain.head.unpack(ptrs)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (Self *ReceiveWindowQueue) Stop() {
|
||||||
|
Self.stopOp <- struct{}{}
|
||||||
|
Self.stopOp <- struct{}{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (Self *ReceiveWindowQueue) SetTimeOut(t time.Time) {
|
||||||
|
Self.timeout = t
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://golang.org/src/sync/poolqueue.go
|
||||||
|
|
||||||
|
type bufDequeue struct {
|
||||||
|
// headTail packs together a 32-bit head index and a 32-bit
|
||||||
|
// tail index. Both are indexes into vals modulo len(vals)-1.
|
||||||
|
//
|
||||||
|
// tail = index of oldest data in queue
|
||||||
|
// head = index of next slot to fill
|
||||||
|
//
|
||||||
|
// Slots in the range [tail, head) are owned by consumers.
|
||||||
|
// A consumer continues to own a slot outside this range until
|
||||||
|
// it nils the slot, at which point ownership passes to the
|
||||||
|
// producer.
|
||||||
|
//
|
||||||
|
// The head index is stored in the most-significant bits so
|
||||||
|
// that we can atomically add to it and the overflow is
|
||||||
|
// harmless.
|
||||||
|
headTail uint64
|
||||||
|
|
||||||
|
// vals is a ring buffer of interface{} values stored in this
|
||||||
|
// dequeue. The size of this must be a power of 2.
|
||||||
|
//
|
||||||
|
// A slot is still in use until *both* the tail
|
||||||
|
// index has moved beyond it and typ has been set to nil. This
|
||||||
|
// is set to nil atomically by the consumer and read
|
||||||
|
// atomically by the producer.
|
||||||
|
vals []unsafe.Pointer
|
||||||
|
starving uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
const dequeueBits = 32
|
||||||
|
|
||||||
|
// dequeueLimit is the maximum size of a bufDequeue.
|
||||||
|
//
|
||||||
|
// This must be at most (1<<dequeueBits)/2 because detecting fullness
|
||||||
|
// depends on wrapping around the ring buffer without wrapping around
|
||||||
|
// the index. We divide by 4 so this fits in an int on 32-bit.
|
||||||
|
const dequeueLimit = (1 << dequeueBits) / 4
|
||||||
|
|
||||||
|
func (d *bufDequeue) unpack(ptrs uint64) (head, tail uint32) {
|
||||||
|
const mask = 1<<dequeueBits - 1
|
||||||
|
head = uint32((ptrs >> dequeueBits) & mask)
|
||||||
|
tail = uint32(ptrs & mask)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *bufDequeue) pack(head, tail uint32) uint64 {
|
||||||
|
const mask = 1<<dequeueBits - 1
|
||||||
|
return (uint64(head) << dequeueBits) |
|
||||||
|
uint64(tail&mask)
|
||||||
|
}
|
||||||
|
|
||||||
|
// pushHead adds val at the head of the queue. It returns false if the
|
||||||
|
// queue is full.
|
||||||
|
func (d *bufDequeue) pushHead(val unsafe.Pointer) bool {
|
||||||
|
var slot *unsafe.Pointer
|
||||||
|
var starve uint8
|
||||||
|
if atomic.LoadUint32(&d.starving) > 0 {
|
||||||
|
runtime.Gosched()
|
||||||
|
}
|
||||||
|
for {
|
||||||
|
ptrs := atomic.LoadUint64(&d.headTail)
|
||||||
|
head, tail := d.unpack(ptrs)
|
||||||
|
if (tail+uint32(len(d.vals)))&(1<<dequeueBits-1) == head {
|
||||||
|
// Queue is full.
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
ptrs2 := d.pack(head+1, tail)
|
||||||
|
if atomic.CompareAndSwapUint64(&d.headTail, ptrs, ptrs2) {
|
||||||
|
slot = &d.vals[head&uint32(len(d.vals)-1)]
|
||||||
|
if starve >= 3 && atomic.LoadUint32(&d.starving) > 0 {
|
||||||
|
atomic.StoreUint32(&d.starving, 0)
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
starve++
|
||||||
|
if starve >= 3 {
|
||||||
|
atomic.StoreUint32(&d.starving, 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// The head slot is free, so we own it.
|
||||||
|
*slot = val
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// popTail removes and returns the element at the tail of the queue.
|
||||||
|
// It returns false if the queue is empty. It may be called by any
|
||||||
|
// number of consumers.
|
||||||
|
func (d *bufDequeue) popTail() (unsafe.Pointer, bool) {
|
||||||
|
ptrs := atomic.LoadUint64(&d.headTail)
|
||||||
|
head, tail := d.unpack(ptrs)
|
||||||
|
if tail == head {
|
||||||
|
// Queue is empty.
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
slot := &d.vals[tail&uint32(len(d.vals)-1)]
|
||||||
|
var val unsafe.Pointer
|
||||||
|
for {
|
||||||
|
val = atomic.LoadPointer(slot)
|
||||||
|
if val != nil {
|
||||||
|
// We now own slot.
|
||||||
|
break
|
||||||
|
}
|
||||||
|
// Another goroutine is still pushing data on the tail.
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tell pushHead that we're done with this slot. Zeroing the
|
||||||
|
// slot is also important so we don't leave behind references
|
||||||
|
// that could keep this object live longer than necessary.
|
||||||
|
//
|
||||||
|
// We write to val first and then publish that we're done with
|
||||||
|
atomic.StorePointer(slot, nil)
|
||||||
|
// At this point pushHead owns the slot.
|
||||||
|
if tail < math.MaxUint32 {
|
||||||
|
atomic.AddUint64(&d.headTail, 1)
|
||||||
|
} else {
|
||||||
|
atomic.AddUint64(&d.headTail, ^uint64(math.MaxUint32-1))
|
||||||
|
}
|
||||||
|
return val, true
|
||||||
|
}
|
||||||
|
|
||||||
|
// bufChain is a dynamically-sized version of bufDequeue.
|
||||||
|
//
|
||||||
|
// This is implemented as a doubly-linked list queue of poolDequeues
|
||||||
|
// where each dequeue is double the size of the previous one. Once a
|
||||||
|
// dequeue fills up, this allocates a new one and only ever pushes to
|
||||||
|
// the latest dequeue. Pops happen from the other end of the list and
|
||||||
|
// once a dequeue is exhausted, it gets removed from the list.
|
||||||
|
type bufChain struct {
|
||||||
|
// head is the bufDequeue to push to. This is only accessed
|
||||||
|
// by the producer, so doesn't need to be synchronized.
|
||||||
|
head *bufChainElt
|
||||||
|
|
||||||
|
// tail is the bufDequeue to popTail from. This is accessed
|
||||||
|
// by consumers, so reads and writes must be atomic.
|
||||||
|
tail *bufChainElt
|
||||||
|
newChain uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
type bufChainElt struct {
|
||||||
|
bufDequeue
|
||||||
|
|
||||||
|
// next and prev link to the adjacent poolChainElts in this
|
||||||
|
// bufChain.
|
||||||
|
//
|
||||||
|
// next is written atomically by the producer and read
|
||||||
|
// atomically by the consumer. It only transitions from nil to
|
||||||
|
// non-nil.
|
||||||
|
//
|
||||||
|
// prev is written atomically by the consumer and read
|
||||||
|
// atomically by the producer. It only transitions from
|
||||||
|
// non-nil to nil.
|
||||||
|
next, prev *bufChainElt
|
||||||
|
}
|
||||||
|
|
||||||
|
func storePoolChainElt(pp **bufChainElt, v *bufChainElt) {
|
||||||
|
atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(pp)), unsafe.Pointer(v))
|
||||||
|
}
|
||||||
|
|
||||||
|
func loadPoolChainElt(pp **bufChainElt) *bufChainElt {
|
||||||
|
return (*bufChainElt)(atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(pp))))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *bufChain) new(initSize int) {
|
||||||
|
// Initialize the chain.
|
||||||
|
// initSize must be a power of 2
|
||||||
|
d := new(bufChainElt)
|
||||||
|
d.vals = make([]unsafe.Pointer, initSize)
|
||||||
|
storePoolChainElt(&c.head, d)
|
||||||
|
storePoolChainElt(&c.tail, d)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *bufChain) pushHead(val unsafe.Pointer) {
|
||||||
|
startPush:
|
||||||
|
for {
|
||||||
|
if atomic.LoadUint32(&c.newChain) > 0 {
|
||||||
|
runtime.Gosched()
|
||||||
|
} else {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
d := loadPoolChainElt(&c.head)
|
||||||
|
|
||||||
|
if d.pushHead(val) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// The current dequeue is full. Allocate a new one of twice
|
||||||
|
// the size.
|
||||||
|
if atomic.CompareAndSwapUint32(&c.newChain, 0, 1) {
|
||||||
|
newSize := len(d.vals) * 2
|
||||||
|
if newSize >= dequeueLimit {
|
||||||
|
// Can't make it any bigger.
|
||||||
|
newSize = dequeueLimit
|
||||||
|
}
|
||||||
|
|
||||||
|
d2 := &bufChainElt{prev: d}
|
||||||
|
d2.vals = make([]unsafe.Pointer, newSize)
|
||||||
|
d2.pushHead(val)
|
||||||
|
storePoolChainElt(&c.head, d2)
|
||||||
|
storePoolChainElt(&d.next, d2)
|
||||||
|
atomic.StoreUint32(&c.newChain, 0)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
goto startPush
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *bufChain) popTail() (unsafe.Pointer, bool) {
|
||||||
|
d := loadPoolChainElt(&c.tail)
|
||||||
|
if d == nil {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
|
||||||
|
for {
|
||||||
|
// It's important that we load the next pointer
|
||||||
|
// *before* popping the tail. In general, d may be
|
||||||
|
// transiently empty, but if next is non-nil before
|
||||||
|
// the TryPop and the TryPop fails, then d is permanently
|
||||||
|
// empty, which is the only condition under which it's
|
||||||
|
// safe to drop d from the chain.
|
||||||
|
d2 := loadPoolChainElt(&d.next)
|
||||||
|
|
||||||
|
if val, ok := d.popTail(); ok {
|
||||||
|
return val, ok
|
||||||
|
}
|
||||||
|
|
||||||
|
if d2 == nil {
|
||||||
|
// This is the only dequeue. It's empty right
|
||||||
|
// now, but could be pushed to in the future.
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
|
||||||
|
// The tail of the chain has been drained, so move on
|
||||||
|
// to the next dequeue. Try to drop it from the chain
|
||||||
|
// so the next TryPop doesn't have to look at the empty
|
||||||
|
// dequeue again.
|
||||||
|
if atomic.CompareAndSwapPointer((*unsafe.Pointer)(unsafe.Pointer(&c.tail)), unsafe.Pointer(d), unsafe.Pointer(d2)) {
|
||||||
|
// We won the race. Clear the prev pointer so
|
||||||
|
// the garbage collector can collect the empty
|
||||||
|
// dequeue and so popHead doesn't back up
|
||||||
|
// further than necessary.
|
||||||
|
storePoolChainElt(&d2.prev, nil)
|
||||||
|
}
|
||||||
|
d = d2
|
||||||
|
}
|
||||||
|
}
|
154
lib/mux/web.go
Normal file
154
lib/mux/web.go
Normal file
@ -0,0 +1,154 @@
|
|||||||
|
package mux
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/astaxie/beego/logs"
|
||||||
|
"net/http"
|
||||||
|
"sort"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type connLog struct {
|
||||||
|
startTime time.Time
|
||||||
|
isClose bool
|
||||||
|
logs []string
|
||||||
|
}
|
||||||
|
|
||||||
|
var logms map[int]*connLog
|
||||||
|
var logmc map[int]*connLog
|
||||||
|
|
||||||
|
var copyMaps map[int]*connLog
|
||||||
|
var copyMapc map[int]*connLog
|
||||||
|
var stashTimeNow time.Time
|
||||||
|
var mutex sync.Mutex
|
||||||
|
|
||||||
|
func deepCopyMaps() {
|
||||||
|
copyMaps = make(map[int]*connLog)
|
||||||
|
for k, v := range logms {
|
||||||
|
copyMaps[k] = &connLog{
|
||||||
|
startTime: v.startTime,
|
||||||
|
isClose: v.isClose,
|
||||||
|
logs: v.logs,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func deepCopyMapc() {
|
||||||
|
copyMapc = make(map[int]*connLog)
|
||||||
|
for k, v := range logmc {
|
||||||
|
copyMapc[k] = &connLog{
|
||||||
|
startTime: v.startTime,
|
||||||
|
isClose: v.isClose,
|
||||||
|
logs: v.logs,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
logms = make(map[int]*connLog)
|
||||||
|
logmc = make(map[int]*connLog)
|
||||||
|
}
|
||||||
|
|
||||||
|
type IntSlice []int
|
||||||
|
|
||||||
|
func (s IntSlice) Len() int { return len(s) }
|
||||||
|
|
||||||
|
func (s IntSlice) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
|
||||||
|
|
||||||
|
func (s IntSlice) Less(i, j int) bool { return s[i] < s[j] }
|
||||||
|
|
||||||
|
func NewLogServer() {
|
||||||
|
http.HandleFunc("/", index)
|
||||||
|
http.HandleFunc("/detail", detail)
|
||||||
|
http.HandleFunc("/stash", stash)
|
||||||
|
fmt.Println(http.ListenAndServe(":8899", nil))
|
||||||
|
}
|
||||||
|
|
||||||
|
func stash(w http.ResponseWriter, r *http.Request) {
|
||||||
|
stashTimeNow = time.Now()
|
||||||
|
deepCopyMaps()
|
||||||
|
deepCopyMapc()
|
||||||
|
w.Write([]byte("ok"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func getM(label string, id int) (cL *connLog) {
|
||||||
|
label = strings.TrimSpace(label)
|
||||||
|
mutex.Lock()
|
||||||
|
defer mutex.Unlock()
|
||||||
|
if label == "nps" {
|
||||||
|
cL = logms[id]
|
||||||
|
}
|
||||||
|
if label == "npc" {
|
||||||
|
cL = logmc[id]
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func setM(label string, id int, cL *connLog) {
|
||||||
|
label = strings.TrimSpace(label)
|
||||||
|
mutex.Lock()
|
||||||
|
defer mutex.Unlock()
|
||||||
|
if label == "nps" {
|
||||||
|
logms[id] = cL
|
||||||
|
}
|
||||||
|
if label == "npc" {
|
||||||
|
logmc[id] = cL
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func index(w http.ResponseWriter, r *http.Request) {
|
||||||
|
var keys []int
|
||||||
|
for k := range copyMaps {
|
||||||
|
keys = append(keys, k)
|
||||||
|
}
|
||||||
|
sort.Sort(IntSlice(keys))
|
||||||
|
var s string
|
||||||
|
s += "<h1>nps</h1>"
|
||||||
|
for _, v := range keys {
|
||||||
|
connL := copyMaps[v]
|
||||||
|
s += "<a href='/detail?id=" + strconv.Itoa(v) + "&label=nps" + "'>" + strconv.Itoa(v) + "</a>----------"
|
||||||
|
s += strconv.Itoa(int(stashTimeNow.Sub(connL.startTime).Milliseconds())) + "ms----------"
|
||||||
|
s += strconv.FormatBool(connL.isClose)
|
||||||
|
s += "<br>"
|
||||||
|
}
|
||||||
|
|
||||||
|
keys = keys[:0]
|
||||||
|
s += "<h1>npc</h1>"
|
||||||
|
for k := range copyMapc {
|
||||||
|
keys = append(keys, k)
|
||||||
|
}
|
||||||
|
sort.Sort(IntSlice(keys))
|
||||||
|
|
||||||
|
for _, v := range keys {
|
||||||
|
connL := copyMapc[v]
|
||||||
|
s += "<a href='/detail?id=" + strconv.Itoa(v) + "&label=npc" + "'>" + strconv.Itoa(v) + "</a>----------"
|
||||||
|
s += strconv.Itoa(int(stashTimeNow.Sub(connL.startTime).Milliseconds())) + "ms----------"
|
||||||
|
s += strconv.FormatBool(connL.isClose)
|
||||||
|
s += "<br>"
|
||||||
|
}
|
||||||
|
w.Write([]byte(s))
|
||||||
|
}
|
||||||
|
|
||||||
|
func detail(w http.ResponseWriter, r *http.Request) {
|
||||||
|
id := r.FormValue("id")
|
||||||
|
label := r.FormValue("label")
|
||||||
|
logs.Warn(label)
|
||||||
|
i, _ := strconv.Atoi(id)
|
||||||
|
var v *connLog
|
||||||
|
if label == "nps" {
|
||||||
|
v, _ = copyMaps[i]
|
||||||
|
}
|
||||||
|
if label == "npc" {
|
||||||
|
v, _ = copyMapc[i]
|
||||||
|
}
|
||||||
|
var s string
|
||||||
|
if v != nil {
|
||||||
|
for i, vv := range v.logs {
|
||||||
|
s += "<p>" + strconv.Itoa(i+1) + ":" + vv + "</p>"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
w.Write([]byte(s))
|
||||||
|
}
|
7
lib/mux/web_test.go
Normal file
7
lib/mux/web_test.go
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
package mux
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
|
||||||
|
func TestWeb(t *testing.T) {
|
||||||
|
NewLogServer()
|
||||||
|
}
|
@ -1,8 +1,8 @@
|
|||||||
package version
|
package version
|
||||||
|
|
||||||
const VERSION = "0.26.10"
|
const VERSION = "0.24.0"
|
||||||
|
|
||||||
// Compulsory minimum version, Minimum downward compatibility to this version
|
// Compulsory minimum version, Minimum downward compatibility to this version
|
||||||
func GetVersion() string {
|
func GetVersion() string {
|
||||||
return "0.26.0"
|
return "0.24.0"
|
||||||
}
|
}
|
||||||
|
@ -5,12 +5,12 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"ehang.io/nps/lib/pmux"
|
|
||||||
"github.com/astaxie/beego"
|
"github.com/astaxie/beego"
|
||||||
"github.com/astaxie/beego/logs"
|
"github.com/astaxie/beego/logs"
|
||||||
|
"github.com/cnlh/nps/lib/mux"
|
||||||
)
|
)
|
||||||
|
|
||||||
var pMux *pmux.PortMux
|
var pMux *mux.PortMux
|
||||||
var bridgePort string
|
var bridgePort string
|
||||||
var httpsPort string
|
var httpsPort string
|
||||||
var httpPort string
|
var httpPort string
|
||||||
@ -28,7 +28,7 @@ func InitConnectionService() {
|
|||||||
logs.Error(err)
|
logs.Error(err)
|
||||||
os.Exit(0)
|
os.Exit(0)
|
||||||
}
|
}
|
||||||
pMux = pmux.NewPortMux(port, beego.AppConfig.String("web_host"))
|
pMux = mux.NewPortMux(port, beego.AppConfig.String("web_host"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,11 +6,11 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"ehang.io/nps/bridge"
|
|
||||||
"ehang.io/nps/lib/common"
|
|
||||||
"ehang.io/nps/lib/conn"
|
|
||||||
"ehang.io/nps/lib/file"
|
|
||||||
"github.com/astaxie/beego/logs"
|
"github.com/astaxie/beego/logs"
|
||||||
|
"github.com/cnlh/nps/bridge"
|
||||||
|
"github.com/cnlh/nps/lib/common"
|
||||||
|
"github.com/cnlh/nps/lib/conn"
|
||||||
|
"github.com/cnlh/nps/lib/file"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Service interface {
|
type Service interface {
|
||||||
|
@ -13,13 +13,13 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"ehang.io/nps/bridge"
|
|
||||||
"ehang.io/nps/lib/cache"
|
|
||||||
"ehang.io/nps/lib/common"
|
|
||||||
"ehang.io/nps/lib/conn"
|
|
||||||
"ehang.io/nps/lib/file"
|
|
||||||
"ehang.io/nps/server/connection"
|
|
||||||
"github.com/astaxie/beego/logs"
|
"github.com/astaxie/beego/logs"
|
||||||
|
"github.com/cnlh/nps/bridge"
|
||||||
|
"github.com/cnlh/nps/lib/cache"
|
||||||
|
"github.com/cnlh/nps/lib/common"
|
||||||
|
"github.com/cnlh/nps/lib/conn"
|
||||||
|
"github.com/cnlh/nps/lib/file"
|
||||||
|
"github.com/cnlh/nps/server/connection"
|
||||||
)
|
)
|
||||||
|
|
||||||
type httpServer struct {
|
type httpServer struct {
|
||||||
@ -30,12 +30,11 @@ type httpServer struct {
|
|||||||
httpsServer *http.Server
|
httpsServer *http.Server
|
||||||
httpsListener net.Listener
|
httpsListener net.Listener
|
||||||
useCache bool
|
useCache bool
|
||||||
addOrigin bool
|
|
||||||
cache *cache.Cache
|
cache *cache.Cache
|
||||||
cacheLen int
|
cacheLen int
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewHttp(bridge *bridge.Bridge, c *file.Tunnel, httpPort, httpsPort int, useCache bool, cacheLen int, addOrigin bool) *httpServer {
|
func NewHttp(bridge *bridge.Bridge, c *file.Tunnel, httpPort, httpsPort int, useCache bool, cacheLen int) *httpServer {
|
||||||
httpServer := &httpServer{
|
httpServer := &httpServer{
|
||||||
BaseServer: BaseServer{
|
BaseServer: BaseServer{
|
||||||
task: c,
|
task: c,
|
||||||
@ -46,7 +45,6 @@ func NewHttp(bridge *bridge.Bridge, c *file.Tunnel, httpPort, httpsPort int, use
|
|||||||
httpsPort: httpsPort,
|
httpsPort: httpsPort,
|
||||||
useCache: useCache,
|
useCache: useCache,
|
||||||
cacheLen: cacheLen,
|
cacheLen: cacheLen,
|
||||||
addOrigin: addOrigin,
|
|
||||||
}
|
}
|
||||||
if useCache {
|
if useCache {
|
||||||
httpServer.cache = cache.New(cacheLen)
|
httpServer.cache = cache.New(cacheLen)
|
||||||
@ -57,7 +55,7 @@ func NewHttp(bridge *bridge.Bridge, c *file.Tunnel, httpPort, httpsPort int, use
|
|||||||
func (s *httpServer) Start() error {
|
func (s *httpServer) Start() error {
|
||||||
var err error
|
var err error
|
||||||
if s.errorContent, err = common.ReadAllFromFile(filepath.Join(common.GetRunPath(), "web", "static", "page", "error.html")); err != nil {
|
if s.errorContent, err = common.ReadAllFromFile(filepath.Join(common.GetRunPath(), "web", "static", "page", "error.html")); err != nil {
|
||||||
s.errorContent = []byte("nps 404")
|
s.errorContent = []byte("easyProxy 404")
|
||||||
}
|
}
|
||||||
if s.httpPort > 0 {
|
if s.httpPort > 0 {
|
||||||
s.httpServer = s.NewServer(s.httpPort, "http")
|
s.httpServer = s.NewServer(s.httpPort, "http")
|
||||||
@ -118,6 +116,7 @@ func (s *httpServer) handleHttp(c *conn.Conn, r *http.Request) {
|
|||||||
var (
|
var (
|
||||||
host *file.Host
|
host *file.Host
|
||||||
target net.Conn
|
target net.Conn
|
||||||
|
lastHost *file.Host
|
||||||
err error
|
err error
|
||||||
connClient io.ReadWriteCloser
|
connClient io.ReadWriteCloser
|
||||||
scheme = r.URL.Scheme
|
scheme = r.URL.Scheme
|
||||||
@ -129,16 +128,11 @@ func (s *httpServer) handleHttp(c *conn.Conn, r *http.Request) {
|
|||||||
)
|
)
|
||||||
defer func() {
|
defer func() {
|
||||||
if connClient != nil {
|
if connClient != nil {
|
||||||
connClient.Close()
|
|
||||||
} else {
|
|
||||||
s.writeConnFail(c.Conn)
|
s.writeConnFail(c.Conn)
|
||||||
|
connClient.Close()
|
||||||
}
|
}
|
||||||
c.Close()
|
c.Close()
|
||||||
}()
|
}()
|
||||||
reset:
|
|
||||||
if isReset {
|
|
||||||
host.Client.AddConn()
|
|
||||||
}
|
|
||||||
if host, err = file.GetDb().GetInfoByHost(r.Host, r); err != nil {
|
if host, err = file.GetDb().GetInfoByHost(r.Host, r); err != nil {
|
||||||
logs.Notice("the url %s %s %s can't be parsed!", r.URL.Scheme, r.Host, r.RequestURI)
|
logs.Notice("the url %s %s %s can't be parsed!", r.URL.Scheme, r.Host, r.RequestURI)
|
||||||
return
|
return
|
||||||
@ -147,13 +141,12 @@ reset:
|
|||||||
logs.Warn("client id %d, host id %d, error %s, when https connection", host.Client.Id, host.Id, err.Error())
|
logs.Warn("client id %d, host id %d, error %s, when https connection", host.Client.Id, host.Id, err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if !isReset {
|
defer host.Client.AddConn()
|
||||||
defer host.Client.AddConn()
|
|
||||||
}
|
|
||||||
if err = s.auth(r, c, host.Client.Cnf.U, host.Client.Cnf.P); err != nil {
|
if err = s.auth(r, c, host.Client.Cnf.U, host.Client.Cnf.P); err != nil {
|
||||||
logs.Warn("auth error", err, r.RemoteAddr)
|
logs.Warn("auth error", err, r.RemoteAddr)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
reset:
|
||||||
if targetAddr, err = host.Target.GetRandomTarget(); err != nil {
|
if targetAddr, err = host.Target.GetRandomTarget(); err != nil {
|
||||||
logs.Warn(err.Error())
|
logs.Warn(err.Error())
|
||||||
return
|
return
|
||||||
@ -164,6 +157,7 @@ reset:
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
connClient = conn.GetConn(target, lk.Crypt, lk.Compress, host.Client.Rate, true)
|
connClient = conn.GetConn(target, lk.Crypt, lk.Compress, host.Client.Rate, true)
|
||||||
|
lastHost = host
|
||||||
|
|
||||||
//read from inc-client
|
//read from inc-client
|
||||||
go func() {
|
go func() {
|
||||||
@ -177,12 +171,11 @@ reset:
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
for {
|
for {
|
||||||
if resp, err := http.ReadResponse(bufio.NewReader(connClient), r); err != nil || resp == nil || r == nil {
|
if resp, err := http.ReadResponse(bufio.NewReader(connClient), r); err != nil {
|
||||||
// if there got broken pipe, http.ReadResponse will get a nil
|
|
||||||
return
|
return
|
||||||
} else {
|
} else {
|
||||||
//if the cache is start and the response is in the extension,store the response to the cache list
|
//if the cache is start and the response is in the extension,store the response to the cache list
|
||||||
if s.useCache && r.URL != nil && strings.Contains(r.URL.Path, ".") {
|
if s.useCache && strings.Contains(r.URL.Path, ".") {
|
||||||
b, err := httputil.DumpResponse(resp, true)
|
b, err := httputil.DumpResponse(resp, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
@ -221,7 +214,7 @@ reset:
|
|||||||
}
|
}
|
||||||
|
|
||||||
//change the host and header and set proxy setting
|
//change the host and header and set proxy setting
|
||||||
common.ChangeHostAndHeader(r, host.HostChange, host.HeaderChange, c.Conn.RemoteAddr().String(), s.addOrigin)
|
common.ChangeHostAndHeader(r, host.HostChange, host.HeaderChange, c.Conn.RemoteAddr().String())
|
||||||
logs.Trace("%s request, method %s, host %s, url %s, remote address %s, target %s", r.URL.Scheme, r.Method, r.Host, r.URL.Path, c.RemoteAddr().String(), lk.Host)
|
logs.Trace("%s request, method %s, host %s, url %s, remote address %s, target %s", r.URL.Scheme, r.Method, r.Host, r.URL.Path, c.RemoteAddr().String(), lk.Host)
|
||||||
//write
|
//write
|
||||||
lenConn = conn.NewLenConn(connClient)
|
lenConn = conn.NewLenConn(connClient)
|
||||||
@ -242,8 +235,9 @@ reset:
|
|||||||
if hostTmp, err := file.GetDb().GetInfoByHost(r.Host, r); err != nil {
|
if hostTmp, err := file.GetDb().GetInfoByHost(r.Host, r); err != nil {
|
||||||
logs.Notice("the url %s %s %s can't be parsed!", r.URL.Scheme, r.Host, r.RequestURI)
|
logs.Notice("the url %s %s %s can't be parsed!", r.URL.Scheme, r.Host, r.RequestURI)
|
||||||
break
|
break
|
||||||
} else if host != hostTmp {
|
} else if host != lastHost {
|
||||||
host = hostTmp
|
host = hostTmp
|
||||||
|
lastHost = host
|
||||||
isReset = true
|
isReset = true
|
||||||
connClient.Close()
|
connClient.Close()
|
||||||
goto reset
|
goto reset
|
||||||
|
@ -6,13 +6,13 @@ import (
|
|||||||
"net/url"
|
"net/url"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"ehang.io/nps/lib/cache"
|
|
||||||
"ehang.io/nps/lib/common"
|
|
||||||
"ehang.io/nps/lib/conn"
|
|
||||||
"ehang.io/nps/lib/crypt"
|
|
||||||
"ehang.io/nps/lib/file"
|
|
||||||
"github.com/astaxie/beego"
|
"github.com/astaxie/beego"
|
||||||
"github.com/astaxie/beego/logs"
|
"github.com/astaxie/beego/logs"
|
||||||
|
"github.com/cnlh/nps/lib/cache"
|
||||||
|
"github.com/cnlh/nps/lib/common"
|
||||||
|
"github.com/cnlh/nps/lib/conn"
|
||||||
|
"github.com/cnlh/nps/lib/crypt"
|
||||||
|
"github.com/cnlh/nps/lib/file"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -5,8 +5,8 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"ehang.io/nps/lib/common"
|
|
||||||
"github.com/astaxie/beego/logs"
|
"github.com/astaxie/beego/logs"
|
||||||
|
"github.com/cnlh/nps/lib/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
type P2PServer struct {
|
type P2PServer struct {
|
||||||
|
@ -7,10 +7,10 @@ import (
|
|||||||
"net"
|
"net"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"ehang.io/nps/lib/common"
|
|
||||||
"ehang.io/nps/lib/conn"
|
|
||||||
"ehang.io/nps/lib/file"
|
|
||||||
"github.com/astaxie/beego/logs"
|
"github.com/astaxie/beego/logs"
|
||||||
|
"github.com/cnlh/nps/lib/common"
|
||||||
|
"github.com/cnlh/nps/lib/conn"
|
||||||
|
"github.com/cnlh/nps/lib/file"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -154,130 +154,27 @@ func (s *Sock5ModeServer) handleConnect(c net.Conn) {
|
|||||||
// passive mode
|
// passive mode
|
||||||
func (s *Sock5ModeServer) handleBind(c net.Conn) {
|
func (s *Sock5ModeServer) handleBind(c net.Conn) {
|
||||||
}
|
}
|
||||||
func (s *Sock5ModeServer) sendUdpReply(writeConn net.Conn, c net.Conn, rep uint8, serverIp string) {
|
|
||||||
reply := []byte{
|
|
||||||
5,
|
|
||||||
rep,
|
|
||||||
0,
|
|
||||||
1,
|
|
||||||
}
|
|
||||||
localHost, localPort, _ := net.SplitHostPort(c.LocalAddr().String())
|
|
||||||
localHost = serverIp
|
|
||||||
ipBytes := net.ParseIP(localHost).To4()
|
|
||||||
nPort, _ := strconv.Atoi(localPort)
|
|
||||||
reply = append(reply, ipBytes...)
|
|
||||||
portBytes := make([]byte, 2)
|
|
||||||
binary.BigEndian.PutUint16(portBytes, uint16(nPort))
|
|
||||||
reply = append(reply, portBytes...)
|
|
||||||
writeConn.Write(reply)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
//udp
|
||||||
func (s *Sock5ModeServer) handleUDP(c net.Conn) {
|
func (s *Sock5ModeServer) handleUDP(c net.Conn) {
|
||||||
defer c.Close()
|
/*
|
||||||
addrType := make([]byte, 1)
|
+----+------+------+----------+----------+----------+
|
||||||
c.Read(addrType)
|
|RSV | FRAG | ATYP | DST.ADDR | DST.PORT | DATA |
|
||||||
var host string
|
+----+------+------+----------+----------+----------+
|
||||||
switch addrType[0] {
|
| 2 | 1 | 1 | Variable | 2 | Variable |
|
||||||
case ipV4:
|
+----+------+------+----------+----------+----------+
|
||||||
ipv4 := make(net.IP, net.IPv4len)
|
*/
|
||||||
c.Read(ipv4)
|
buf := make([]byte, 3)
|
||||||
host = ipv4.String()
|
c.Read(buf)
|
||||||
case ipV6:
|
// relay udp datagram silently, without any notification to the requesting client
|
||||||
ipv6 := make(net.IP, net.IPv6len)
|
if buf[2] != 0 {
|
||||||
c.Read(ipv6)
|
// does not support fragmentation, drop it
|
||||||
host = ipv6.String()
|
logs.Warn("does not support fragmentation, drop")
|
||||||
case domainName:
|
dummy := make([]byte, maxUDPPacketSize)
|
||||||
var domainLen uint8
|
c.Read(dummy)
|
||||||
binary.Read(c, binary.BigEndian, &domainLen)
|
|
||||||
domain := make([]byte, domainLen)
|
|
||||||
c.Read(domain)
|
|
||||||
host = string(domain)
|
|
||||||
default:
|
|
||||||
s.sendReply(c, addrTypeNotSupported)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
//读取端口
|
|
||||||
var port uint16
|
|
||||||
binary.Read(c, binary.BigEndian, &port)
|
|
||||||
logs.Warn(host, string(port))
|
|
||||||
replyAddr, err := net.ResolveUDPAddr("udp", s.task.ServerIp+":0")
|
|
||||||
if err != nil {
|
|
||||||
logs.Error("build local reply addr error", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
reply, err := net.ListenUDP("udp", replyAddr)
|
|
||||||
if err != nil {
|
|
||||||
s.sendReply(c, addrTypeNotSupported)
|
|
||||||
logs.Error("listen local reply udp port error")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// reply the local addr
|
|
||||||
s.sendUdpReply(c, reply, succeeded, common.GetServerIpByClientIp(c.RemoteAddr().(*net.TCPAddr).IP))
|
|
||||||
defer reply.Close()
|
|
||||||
// new a tunnel to client
|
|
||||||
link := conn.NewLink("udp5", "", s.task.Client.Cnf.Crypt, s.task.Client.Cnf.Compress, c.RemoteAddr().String(), false)
|
|
||||||
target, err := s.bridge.SendLinkInfo(s.task.Client.Id, link, s.task)
|
|
||||||
if err != nil {
|
|
||||||
logs.Warn("get connection from client id %d error %s", s.task.Client.Id, err.Error())
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var clientAddr net.Addr
|
s.doConnect(c, associateMethod)
|
||||||
// copy buffer
|
|
||||||
go func() {
|
|
||||||
b := common.BufPoolUdp.Get().([]byte)
|
|
||||||
defer common.BufPoolUdp.Put(b)
|
|
||||||
defer c.Close()
|
|
||||||
|
|
||||||
for {
|
|
||||||
n, laddr, err := reply.ReadFrom(b)
|
|
||||||
if err != nil {
|
|
||||||
logs.Error("read data from %s err %s", reply.LocalAddr().String(), err.Error())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if clientAddr == nil {
|
|
||||||
clientAddr = laddr
|
|
||||||
}
|
|
||||||
if _, err := target.Write(b[:n]); err != nil {
|
|
||||||
logs.Error("write data to client error", err.Error())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
go func() {
|
|
||||||
var l int32
|
|
||||||
b := common.BufPoolUdp.Get().([]byte)
|
|
||||||
defer common.BufPoolUdp.Put(b)
|
|
||||||
defer c.Close()
|
|
||||||
for {
|
|
||||||
if err := binary.Read(target, binary.LittleEndian, &l); err != nil || l >= common.PoolSizeUdp || l <= 0 {
|
|
||||||
logs.Warn("read len bytes error", err.Error())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
binary.Read(target, binary.LittleEndian, b[:l])
|
|
||||||
if err != nil {
|
|
||||||
logs.Warn("read data form client error", err.Error())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if _, err := reply.WriteTo(b[:l], clientAddr); err != nil {
|
|
||||||
logs.Warn("write data to user ", err.Error())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
b := common.BufPoolUdp.Get().([]byte)
|
|
||||||
defer common.BufPoolUdp.Put(b)
|
|
||||||
defer target.Close()
|
|
||||||
for {
|
|
||||||
_, err := c.Read(b)
|
|
||||||
if err != nil {
|
|
||||||
c.Close()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//new conn
|
//new conn
|
||||||
|
@ -7,13 +7,13 @@ import (
|
|||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"ehang.io/nps/bridge"
|
|
||||||
"ehang.io/nps/lib/common"
|
|
||||||
"ehang.io/nps/lib/conn"
|
|
||||||
"ehang.io/nps/lib/file"
|
|
||||||
"ehang.io/nps/server/connection"
|
|
||||||
"github.com/astaxie/beego"
|
"github.com/astaxie/beego"
|
||||||
"github.com/astaxie/beego/logs"
|
"github.com/astaxie/beego/logs"
|
||||||
|
"github.com/cnlh/nps/bridge"
|
||||||
|
"github.com/cnlh/nps/lib/common"
|
||||||
|
"github.com/cnlh/nps/lib/conn"
|
||||||
|
"github.com/cnlh/nps/lib/file"
|
||||||
|
"github.com/cnlh/nps/server/connection"
|
||||||
)
|
)
|
||||||
|
|
||||||
type TunnelModeServer struct {
|
type TunnelModeServer struct {
|
||||||
@ -63,23 +63,15 @@ func (s *WebServer) Start() error {
|
|||||||
<-stop
|
<-stop
|
||||||
}
|
}
|
||||||
beego.BConfig.WebConfig.Session.SessionOn = true
|
beego.BConfig.WebConfig.Session.SessionOn = true
|
||||||
beego.SetStaticPath(beego.AppConfig.String("web_base_url")+"/static", filepath.Join(common.GetRunPath(), "web", "static"))
|
beego.SetStaticPath("/static", filepath.Join(common.GetRunPath(), "web", "static"))
|
||||||
beego.SetViewsPath(filepath.Join(common.GetRunPath(), "web", "views"))
|
beego.SetViewsPath(filepath.Join(common.GetRunPath(), "web", "views"))
|
||||||
err := errors.New("Web management startup failure ")
|
if l, err := connection.GetWebManagerListener(); err == nil {
|
||||||
var l net.Listener
|
|
||||||
if l, err = connection.GetWebManagerListener(); err == nil {
|
|
||||||
beego.InitBeforeHTTPRun()
|
beego.InitBeforeHTTPRun()
|
||||||
if beego.AppConfig.String("web_open_ssl") == "true" {
|
http.Serve(l, beego.BeeApp.Handlers)
|
||||||
keyPath := beego.AppConfig.String("web_key_file")
|
|
||||||
certPath := beego.AppConfig.String("web_cert_file")
|
|
||||||
err = http.ServeTLS(l, beego.BeeApp.Handlers, certPath, keyPath)
|
|
||||||
} else {
|
|
||||||
err = http.Serve(l, beego.BeeApp.Handlers)
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
logs.Error(err)
|
logs.Error(err)
|
||||||
}
|
}
|
||||||
return err
|
return errors.New("Web management startup failure")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *WebServer) Close() error {
|
func (s *WebServer) Close() error {
|
||||||
|
@ -7,8 +7,8 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
"ehang.io/nps/lib/common"
|
"github.com/cnlh/nps/lib/common"
|
||||||
"ehang.io/nps/lib/conn"
|
"github.com/cnlh/nps/lib/conn"
|
||||||
)
|
)
|
||||||
|
|
||||||
func HandleTrans(c *conn.Conn, s *TunnelModeServer) error {
|
func HandleTrans(c *conn.Conn, s *TunnelModeServer) error {
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
package proxy
|
package proxy
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"ehang.io/nps/lib/conn"
|
"github.com/cnlh/nps/lib/conn"
|
||||||
)
|
)
|
||||||
|
|
||||||
func HandleTrans(c *conn.Conn, s *TunnelModeServer) error {
|
func HandleTrans(c *conn.Conn, s *TunnelModeServer) error {
|
||||||
|
@ -1,22 +1,18 @@
|
|||||||
package proxy
|
package proxy
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io"
|
|
||||||
"net"
|
"net"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"ehang.io/nps/bridge"
|
|
||||||
"ehang.io/nps/lib/common"
|
|
||||||
"ehang.io/nps/lib/conn"
|
|
||||||
"ehang.io/nps/lib/file"
|
|
||||||
"github.com/astaxie/beego/logs"
|
"github.com/astaxie/beego/logs"
|
||||||
|
"github.com/cnlh/nps/bridge"
|
||||||
|
"github.com/cnlh/nps/lib/common"
|
||||||
|
"github.com/cnlh/nps/lib/conn"
|
||||||
|
"github.com/cnlh/nps/lib/file"
|
||||||
)
|
)
|
||||||
|
|
||||||
type UdpModeServer struct {
|
type UdpModeServer struct {
|
||||||
BaseServer
|
BaseServer
|
||||||
addrMap sync.Map
|
|
||||||
listener *net.UDPConn
|
listener *net.UDPConn
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -37,8 +33,8 @@ func (s *UdpModeServer) Start() error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
buf := common.BufPoolUdp.Get().([]byte)
|
||||||
for {
|
for {
|
||||||
buf := common.BufPoolUdp.Get().([]byte)
|
|
||||||
n, addr, err := s.listener.ReadFromUDP(buf)
|
n, addr, err := s.listener.ReadFromUDP(buf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if strings.Contains(err.Error(), "use of closed network connection") {
|
if strings.Contains(err.Error(), "use of closed network connection") {
|
||||||
@ -53,43 +49,26 @@ func (s *UdpModeServer) Start() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *UdpModeServer) process(addr *net.UDPAddr, data []byte) {
|
func (s *UdpModeServer) process(addr *net.UDPAddr, data []byte) {
|
||||||
if v, ok := s.addrMap.Load(addr.String()); ok {
|
if err := s.CheckFlowAndConnNum(s.task.Client); err != nil {
|
||||||
clientConn, ok := v.(io.ReadWriteCloser)
|
logs.Warn("client id %d, task id %d,error %s, when udp connection", s.task.Client.Id, s.task.Id, err.Error())
|
||||||
if ok {
|
return
|
||||||
clientConn.Write(data)
|
}
|
||||||
s.task.Flow.Add(int64(len(data)), 0)
|
defer s.task.Client.AddConn()
|
||||||
}
|
link := conn.NewLink(common.CONN_UDP, s.task.Target.TargetStr, s.task.Client.Cnf.Crypt, s.task.Client.Cnf.Compress, addr.String(), s.task.Target.LocalProxy)
|
||||||
|
if target, err := s.bridge.SendLinkInfo(s.task.Client.Id, link, s.task); err != nil {
|
||||||
|
return
|
||||||
} else {
|
} else {
|
||||||
if err := s.CheckFlowAndConnNum(s.task.Client); err != nil {
|
s.task.Flow.Add(int64(len(data)), 0)
|
||||||
logs.Warn("client id %d, task id %d,error %s, when udp connection", s.task.Client.Id, s.task.Id, err.Error())
|
buf := common.BufPoolUdp.Get().([]byte)
|
||||||
return
|
defer common.BufPoolUdp.Put(buf)
|
||||||
}
|
target.Write(data)
|
||||||
defer s.task.Client.AddConn()
|
s.task.Flow.Add(int64(len(data)), 0)
|
||||||
link := conn.NewLink(common.CONN_UDP, s.task.Target.TargetStr, s.task.Client.Cnf.Crypt, s.task.Client.Cnf.Compress, addr.String(), s.task.Target.LocalProxy)
|
if n, err := target.Read(buf); err != nil {
|
||||||
if clientConn, err := s.bridge.SendLinkInfo(s.task.Client.Id, link, s.task); err != nil {
|
logs.Warn(err)
|
||||||
return
|
return
|
||||||
} else {
|
} else {
|
||||||
target := conn.GetConn(clientConn, s.task.Client.Cnf.Crypt, s.task.Client.Cnf.Compress, nil, true)
|
s.listener.WriteTo(buf[:n], addr)
|
||||||
s.addrMap.Store(addr.String(), target)
|
s.task.Flow.Add(0, int64(n))
|
||||||
defer target.Close()
|
|
||||||
|
|
||||||
target.Write(data)
|
|
||||||
|
|
||||||
buf := common.BufPoolUdp.Get().([]byte)
|
|
||||||
defer common.BufPoolUdp.Put(buf)
|
|
||||||
|
|
||||||
s.task.Flow.Add(int64(len(data)), 0)
|
|
||||||
for {
|
|
||||||
clientConn.SetReadDeadline(time.Now().Add(time.Minute * 10))
|
|
||||||
if n, err := target.Read(buf); err != nil {
|
|
||||||
s.addrMap.Delete(addr.String())
|
|
||||||
logs.Warn(err)
|
|
||||||
return
|
|
||||||
} else {
|
|
||||||
s.listener.WriteTo(buf[:n], addr)
|
|
||||||
s.task.Flow.Add(0, int64(n))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,35 +1,33 @@
|
|||||||
package server
|
package server
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"ehang.io/nps/lib/version"
|
|
||||||
"errors"
|
"errors"
|
||||||
"math"
|
"math"
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"ehang.io/nps/bridge"
|
|
||||||
"ehang.io/nps/lib/common"
|
|
||||||
"ehang.io/nps/lib/file"
|
|
||||||
"ehang.io/nps/server/proxy"
|
|
||||||
"ehang.io/nps/server/tool"
|
|
||||||
"github.com/astaxie/beego"
|
"github.com/astaxie/beego"
|
||||||
"github.com/astaxie/beego/logs"
|
"github.com/astaxie/beego/logs"
|
||||||
"github.com/shirou/gopsutil/v3/cpu"
|
"github.com/cnlh/nps/bridge"
|
||||||
"github.com/shirou/gopsutil/v3/load"
|
"github.com/cnlh/nps/lib/common"
|
||||||
"github.com/shirou/gopsutil/v3/mem"
|
"github.com/cnlh/nps/lib/file"
|
||||||
"github.com/shirou/gopsutil/v3/net"
|
"github.com/cnlh/nps/server/proxy"
|
||||||
|
"github.com/cnlh/nps/server/tool"
|
||||||
|
"github.com/shirou/gopsutil/cpu"
|
||||||
|
"github.com/shirou/gopsutil/load"
|
||||||
|
"github.com/shirou/gopsutil/mem"
|
||||||
|
"github.com/shirou/gopsutil/net"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
Bridge *bridge.Bridge
|
Bridge *bridge.Bridge
|
||||||
RunList sync.Map //map[int]interface{}
|
RunList map[int]interface{}
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
RunList = sync.Map{}
|
RunList = make(map[int]interface{})
|
||||||
}
|
}
|
||||||
|
|
||||||
//init task from db
|
//init task from db
|
||||||
@ -38,8 +36,7 @@ func InitFromCsv() {
|
|||||||
if vkey := beego.AppConfig.String("public_vkey"); vkey != "" {
|
if vkey := beego.AppConfig.String("public_vkey"); vkey != "" {
|
||||||
c := file.NewClient(vkey, true, true)
|
c := file.NewClient(vkey, true, true)
|
||||||
file.GetDb().NewClient(c)
|
file.GetDb().NewClient(c)
|
||||||
RunList.Store(c.Id, nil)
|
RunList[c.Id] = nil
|
||||||
//RunList[c.Id] = nil
|
|
||||||
}
|
}
|
||||||
//Initialize services in server-side files
|
//Initialize services in server-side files
|
||||||
file.GetDb().JsonDb.Tasks.Range(func(key, value interface{}) bool {
|
file.GetDb().JsonDb.Tasks.Range(func(key, value interface{}) bool {
|
||||||
@ -85,8 +82,8 @@ func DealBridgeTask() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//start a new server
|
//start a new server
|
||||||
func StartNewServer(bridgePort int, cnf *file.Tunnel, bridgeType string, bridgeDisconnect int) {
|
func StartNewServer(bridgePort int, cnf *file.Tunnel, bridgeType string) {
|
||||||
Bridge = bridge.NewTunnel(bridgePort, bridgeType, common.GetBoolByStr(beego.AppConfig.String("ip_limit")), RunList, bridgeDisconnect)
|
Bridge = bridge.NewTunnel(bridgePort, bridgeType, common.GetBoolByStr(beego.AppConfig.String("ip_limit")), RunList)
|
||||||
go func() {
|
go func() {
|
||||||
if err := Bridge.StartTunnel(); err != nil {
|
if err := Bridge.StartTunnel(); err != nil {
|
||||||
logs.Error("start server bridge error", err)
|
logs.Error("start server bridge error", err)
|
||||||
@ -104,8 +101,7 @@ func StartNewServer(bridgePort int, cnf *file.Tunnel, bridgeType string, bridgeD
|
|||||||
if err := svr.Start(); err != nil {
|
if err := svr.Start(); err != nil {
|
||||||
logs.Error(err)
|
logs.Error(err)
|
||||||
}
|
}
|
||||||
RunList.Store(cnf.Id, svr)
|
RunList[cnf.Id] = svr
|
||||||
//RunList[cnf.Id] = svr
|
|
||||||
} else {
|
} else {
|
||||||
logs.Error("Incorrect startup mode %s", cnf.Mode)
|
logs.Error("Incorrect startup mode %s", cnf.Mode)
|
||||||
}
|
}
|
||||||
@ -113,7 +109,6 @@ func StartNewServer(bridgePort int, cnf *file.Tunnel, bridgeType string, bridgeD
|
|||||||
|
|
||||||
func dealClientFlow() {
|
func dealClientFlow() {
|
||||||
ticker := time.NewTicker(time.Minute)
|
ticker := time.NewTicker(time.Minute)
|
||||||
defer ticker.Stop()
|
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-ticker.C:
|
case <-ticker.C:
|
||||||
@ -150,16 +145,14 @@ func NewMode(Bridge *bridge.Bridge, c *file.Tunnel) proxy.Service {
|
|||||||
httpsPort, _ := beego.AppConfig.Int("https_proxy_port")
|
httpsPort, _ := beego.AppConfig.Int("https_proxy_port")
|
||||||
useCache, _ := beego.AppConfig.Bool("http_cache")
|
useCache, _ := beego.AppConfig.Bool("http_cache")
|
||||||
cacheLen, _ := beego.AppConfig.Int("http_cache_length")
|
cacheLen, _ := beego.AppConfig.Int("http_cache_length")
|
||||||
addOrigin, _ := beego.AppConfig.Bool("http_add_origin_header")
|
service = proxy.NewHttp(Bridge, c, httpPort, httpsPort, useCache, cacheLen)
|
||||||
service = proxy.NewHttp(Bridge, c, httpPort, httpsPort, useCache, cacheLen, addOrigin)
|
|
||||||
}
|
}
|
||||||
return service
|
return service
|
||||||
}
|
}
|
||||||
|
|
||||||
//stop server
|
//stop server
|
||||||
func StopServer(id int) error {
|
func StopServer(id int) error {
|
||||||
//if v, ok := RunList[id]; ok {
|
if v, ok := RunList[id]; ok {
|
||||||
if v, ok := RunList.Load(id); ok {
|
|
||||||
if svr, ok := v.(proxy.Service); ok {
|
if svr, ok := v.(proxy.Service); ok {
|
||||||
if err := svr.Close(); err != nil {
|
if err := svr.Close(); err != nil {
|
||||||
return err
|
return err
|
||||||
@ -174,8 +167,7 @@ func StopServer(id int) error {
|
|||||||
t.Status = false
|
t.Status = false
|
||||||
file.GetDb().UpdateTask(t)
|
file.GetDb().UpdateTask(t)
|
||||||
}
|
}
|
||||||
//delete(RunList, id)
|
delete(RunList, id)
|
||||||
RunList.Delete(id)
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return errors.New("task is not running")
|
return errors.New("task is not running")
|
||||||
@ -185,8 +177,7 @@ func StopServer(id int) error {
|
|||||||
func AddTask(t *file.Tunnel) error {
|
func AddTask(t *file.Tunnel) error {
|
||||||
if t.Mode == "secret" || t.Mode == "p2p" {
|
if t.Mode == "secret" || t.Mode == "p2p" {
|
||||||
logs.Info("secret task %s start ", t.Remark)
|
logs.Info("secret task %s start ", t.Remark)
|
||||||
//RunList[t.Id] = nil
|
RunList[t.Id] = nil
|
||||||
RunList.Store(t.Id, nil)
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if b := tool.TestServerPort(t.Port, t.Mode); !b && t.Mode != "httpHostServer" {
|
if b := tool.TestServerPort(t.Port, t.Mode); !b && t.Mode != "httpHostServer" {
|
||||||
@ -198,13 +189,11 @@ func AddTask(t *file.Tunnel) error {
|
|||||||
}
|
}
|
||||||
if svr := NewMode(Bridge, t); svr != nil {
|
if svr := NewMode(Bridge, t); svr != nil {
|
||||||
logs.Info("tunnel task %s start mode:%s port %d", t.Remark, t.Mode, t.Port)
|
logs.Info("tunnel task %s start mode:%s port %d", t.Remark, t.Mode, t.Port)
|
||||||
//RunList[t.Id] = svr
|
RunList[t.Id] = svr
|
||||||
RunList.Store(t.Id, svr)
|
|
||||||
go func() {
|
go func() {
|
||||||
if err := svr.Start(); err != nil {
|
if err := svr.Start(); err != nil {
|
||||||
logs.Error("clientId %d taskId %d start error %s", t.Client.Id, t.Id, err)
|
logs.Error("clientId %d taskId %d start error %s", t.Client.Id, t.Id, err)
|
||||||
//delete(RunList, t.Id)
|
delete(RunList, t.Id)
|
||||||
RunList.Delete(t.Id)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
@ -228,8 +217,7 @@ func StartTask(id int) error {
|
|||||||
|
|
||||||
//delete task
|
//delete task
|
||||||
func DelTask(id int) error {
|
func DelTask(id int) error {
|
||||||
//if _, ok := RunList[id]; ok {
|
if _, ok := RunList[id]; ok {
|
||||||
if _, ok := RunList.Load(id); ok {
|
|
||||||
if err := StopServer(id); err != nil {
|
if err := StopServer(id); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -259,8 +247,7 @@ func GetTunnel(start, length int, typeVal string, clientId int, search string) (
|
|||||||
}
|
}
|
||||||
if start--; start < 0 {
|
if start--; start < 0 {
|
||||||
if length--; length >= 0 {
|
if length--; length >= 0 {
|
||||||
//if _, ok := RunList[v.Id]; ok {
|
if _, ok := RunList[v.Id]; ok {
|
||||||
if _, ok := RunList.Load(v.Id); ok {
|
|
||||||
v.RunStatus = true
|
v.RunStatus = true
|
||||||
} else {
|
} else {
|
||||||
v.RunStatus = false
|
v.RunStatus = false
|
||||||
@ -283,9 +270,8 @@ func GetClientList(start, length int, search, sort, order string, clientId int)
|
|||||||
func dealClientData() {
|
func dealClientData() {
|
||||||
file.GetDb().JsonDb.Clients.Range(func(key, value interface{}) bool {
|
file.GetDb().JsonDb.Clients.Range(func(key, value interface{}) bool {
|
||||||
v := value.(*file.Client)
|
v := value.(*file.Client)
|
||||||
if vv, ok := Bridge.Client.Load(v.Id); ok {
|
if _, ok := Bridge.Client.Load(v.Id); ok {
|
||||||
v.IsConnect = true
|
v.IsConnect = true
|
||||||
v.Version = vv.(*bridge.Client).Version
|
|
||||||
} else {
|
} else {
|
||||||
v.IsConnect = false
|
v.IsConnect = false
|
||||||
}
|
}
|
||||||
@ -351,12 +337,8 @@ func DelClientConnect(clientId int) {
|
|||||||
|
|
||||||
func GetDashboardData() map[string]interface{} {
|
func GetDashboardData() map[string]interface{} {
|
||||||
data := make(map[string]interface{})
|
data := make(map[string]interface{})
|
||||||
data["version"] = version.VERSION
|
|
||||||
data["hostCount"] = common.GeSynctMapLen(file.GetDb().JsonDb.Hosts)
|
data["hostCount"] = common.GeSynctMapLen(file.GetDb().JsonDb.Hosts)
|
||||||
data["clientCount"] = common.GeSynctMapLen(file.GetDb().JsonDb.Clients)
|
data["clientCount"] = common.GeSynctMapLen(file.GetDb().JsonDb.Clients) - 1 //Remove the public key client
|
||||||
if beego.AppConfig.String("public_vkey") != "" { //remove public vkey
|
|
||||||
data["clientCount"] = data["clientCount"].(int) - 1
|
|
||||||
}
|
|
||||||
dealClientData()
|
dealClientData()
|
||||||
c := 0
|
c := 0
|
||||||
var in, out int64
|
var in, out int64
|
||||||
@ -448,7 +430,6 @@ func GetDashboardData() map[string]interface{} {
|
|||||||
|
|
||||||
func flowSession(m time.Duration) {
|
func flowSession(m time.Duration) {
|
||||||
ticker := time.NewTicker(m)
|
ticker := time.NewTicker(m)
|
||||||
defer ticker.Stop()
|
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-ticker.C:
|
case <-ticker.C:
|
||||||
|
@ -5,9 +5,9 @@ import (
|
|||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"ehang.io/nps/lib/common"
|
|
||||||
"ehang.io/nps/lib/file"
|
|
||||||
"github.com/astaxie/beego"
|
"github.com/astaxie/beego"
|
||||||
|
"github.com/cnlh/nps/lib/common"
|
||||||
|
"github.com/cnlh/nps/lib/file"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestServerConfig() {
|
func TestServerConfig() {
|
||||||
@ -52,10 +52,10 @@ func TestServerConfig() {
|
|||||||
if port, err := strconv.Atoi(p); err != nil {
|
if port, err := strconv.Atoi(p); err != nil {
|
||||||
log.Fatalln("get https port error", err)
|
log.Fatalln("get https port error", err)
|
||||||
} else {
|
} else {
|
||||||
if beego.AppConfig.String("pemPath") != "" && !common.FileExists(filepath.Join(common.GetRunPath(), beego.AppConfig.String("pemPath"))) {
|
if !common.FileExists(filepath.Join(common.GetRunPath(), beego.AppConfig.String("pemPath"))) {
|
||||||
log.Fatalf("ssl certFile %s is not exist", beego.AppConfig.String("pemPath"))
|
log.Fatalf("ssl certFile %s is not exist", beego.AppConfig.String("pemPath"))
|
||||||
}
|
}
|
||||||
if beego.AppConfig.String("keyPath") != "" && !common.FileExists(filepath.Join(common.GetRunPath(), beego.AppConfig.String("keyPath"))) {
|
if !common.FileExists(filepath.Join(common.GetRunPath(), beego.AppConfig.String("ketPath"))) {
|
||||||
log.Fatalf("ssl keyFile %s is not exist", beego.AppConfig.String("pemPath"))
|
log.Fatalf("ssl keyFile %s is not exist", beego.AppConfig.String("pemPath"))
|
||||||
}
|
}
|
||||||
isInArr(&postTcpArr, port, "http port", "tcp")
|
isInArr(&postTcpArr, port, "http port", "tcp")
|
||||||
|
@ -5,12 +5,12 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"ehang.io/nps/lib/common"
|
|
||||||
"github.com/astaxie/beego"
|
"github.com/astaxie/beego"
|
||||||
"github.com/shirou/gopsutil/v3/cpu"
|
"github.com/cnlh/nps/lib/common"
|
||||||
"github.com/shirou/gopsutil/v3/load"
|
"github.com/shirou/gopsutil/cpu"
|
||||||
"github.com/shirou/gopsutil/v3/mem"
|
"github.com/shirou/gopsutil/load"
|
||||||
"github.com/shirou/gopsutil/v3/net"
|
"github.com/shirou/gopsutil/mem"
|
||||||
|
"github.com/shirou/gopsutil/net"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -31,9 +31,6 @@ func InitAllowPort() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestServerPort(p int, m string) (b bool) {
|
func TestServerPort(p int, m string) (b bool) {
|
||||||
if m == "p2p" || m == "secret" {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
if p > 65535 || p < 0 {
|
if p > 65535 || p < 0 {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
@ -4,8 +4,8 @@ import (
|
|||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"ehang.io/nps/lib/crypt"
|
|
||||||
"github.com/astaxie/beego"
|
"github.com/astaxie/beego"
|
||||||
|
"github.com/cnlh/nps/lib/crypt"
|
||||||
)
|
)
|
||||||
|
|
||||||
type AuthController struct {
|
type AuthController struct {
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user