稳定v1.0.0版本

This commit is contained in:
huangsimin 2018-08-09 12:51:49 +08:00
parent b4383c9240
commit e97e8c903a
5 changed files with 384 additions and 0 deletions

156
dutiesnet.go Normal file
View File

@ -0,0 +1,156 @@
package main
import (
"log"
"net"
"os/exec"
"strings"
"sync/atomic"
"time"
)
// DutiesNet 保证PPPoe可行
type DutiesNet struct {
PW *PingWorker
NetProtectTime int64 // 当前时间大于保护时间,才能进行重启的计算操作(pppoe最大重启保护时间, 保证重启后不会重复接受重启命令而造成不停重启 )
MaxProtectTime int64 // NetProtectTime保护时间的最大值
CmdRestart int64 // 只要大于MaxRestart就重启
MaxRestart int64 // 达到这个值就重启
}
// Default 设置默认值
func (duties *DutiesNet) Default(pw *PingWorker) {
duties.PW = pw
atomic.StoreInt64(&duties.MaxProtectTime, 15)
atomic.StoreInt64(&duties.CmdRestart, 0)
duties.MaxRestart = 4
go duties.Duties()
}
// IsPPP0Up Pppoe是否是UP的状态
func (duties *DutiesNet) IsPPP0Up() bool {
ifaces, err := net.Interfaces()
if ErrorLog(err) {
return false
}
for _, i := range ifaces {
if i.Name == "ppp0" {
flags := strings.Split(i.Flags.String(), "|")
if len(flags) > 0 {
log.Println(flags)
if flags[0] != "up" {
return false
}
}
}
}
return true
}
// IsPPP1Exist ppp1是否是UP的状态
func (duties *DutiesNet) IsPPP1Exist() bool {
ifaces, err := net.Interfaces()
if ErrorLog(err) {
return false
}
for _, i := range ifaces {
if i.Name == "ppp1" {
return true
}
}
return false
}
// PPP0Restart ppp0 重启
func (duties *DutiesNet) PPP0Restart() {
log.Println("PPP0Restart")
_, err := exec.Command("ifdown", "ppp1").Output()
ErrorLog(err)
_, err = exec.Command("ifdown", "ppp0").Output()
ErrorLog(err)
time.Sleep(time.Second * 1)
_, err = exec.Command("ifdown", "ppp0").Output()
ErrorLog(err)
time.Sleep(time.Second * 1)
_, err = exec.Command("ifup", "ppp0").Output()
ErrorLog(err)
time.Sleep(time.Second * 5)
_, err = exec.Command("ip", "route", "replace", "default", "dev", "ppp0").CombinedOutput()
ErrorLog(err)
atomic.StoreInt64(&duties.NetProtectTime, time.Now().Unix()+duties.MaxProtectTime)
atomic.StoreInt64(&duties.CmdRestart, 0)
}
// SetRestart 设置重启 异步
func (duties *DutiesNet) SetRestart() {
log.Println("SetRestart")
now := time.Now().Unix()
// 当前时间大于保护时间,才能进行重启的计算操作
if now >= duties.NetProtectTime {
log.Println("SetRestart Success")
atomic.AddInt64(&duties.CmdRestart, duties.MaxRestart+20) // 设置超过最大的值的20, 保证重启.
}
}
func (duties *DutiesNet) checkError1() bool {
if duties.IsPPP1Exist() {
log.Println("IsPPP1Exist not")
duties.PPP0Restart()
return true
}
return false // 检测错误才返回true 否则 false
}
func (duties *DutiesNet) checkError2() bool {
// 检测3次ppp0是否处于Up的状态(pppoe有可能存在Down的状态, 这种错误. 但是判断为已经成功拨号)
for i := 0; i < 4; i++ {
if duties.IsPPP0Up() {
return false
}
if i == 3 {
log.Println("IsPPP0Up not")
duties.PPP0Restart() // 强制重启, 不受最大值的限制
return true
}
time.Sleep(time.Second * 1)
}
return false
}
//Duties 核心循环过程, 保证pppoe的网络可行
func (duties *DutiesNet) Duties() {
for {
// 如果超过MaxRestart也会重启
if atomic.LoadInt64(&duties.CmdRestart) > duties.MaxRestart {
log.Println("CmdRestart ", atomic.LoadInt64(&duties.CmdRestart))
duties.PPP0Restart()
}
time.Sleep(time.Second * 2)
// 如果网络不能ping通 执行下面的处理
if !duties.PW.PingNet() {
time.Sleep(time.Second * 1)
atomic.AddInt64(&duties.CmdRestart, 1) // 重启因素的积累, 出一次错误就积累一次. 达到最大值后重启
if duties.checkError1() {
continue
}
if duties.checkError2() {
continue
}
} else {
if atomic.LoadInt64(&duties.CmdRestart) > 0 {
atomic.AddInt64(&duties.CmdRestart, -1) // 如果Ping成功就减少重启因素积累. 0为最低限制值
}
}
}
}

54
dutiesvpn.go Normal file
View File

@ -0,0 +1,54 @@
package main
import (
"os/exec"
"sync/atomic"
"time"
)
// DutiesVPN VPN相关的责任
type DutiesVPN struct {
PW *PingWorker
VPNProtectTime int64 // 保护时间
MaxProtectTime int64 // 保护时间的最大值
}
// Default 设置默认值
func (duties *DutiesVPN) Default(pw *PingWorker) {
duties.PW = pw
atomic.StoreInt64(&duties.MaxProtectTime, 40) //保护时间初始化为40秒
go duties.Duties()
}
//Reset 重置
func (duties *DutiesVPN) Reset() {
atomic.StoreInt64(&duties.VPNProtectTime, time.Now().Unix())
}
// RestartConnect 重置Openvpn连接
func (duties *DutiesVPN) RestartConnect() {
_, err := exec.Command("pkill", "openvpn").CombinedOutput()
ErrorLog(err)
atomic.StoreInt64(&duties.VPNProtectTime, time.Now().Unix()+duties.MaxProtectTime) //重启后给予40秒openvpn的重试时间
}
// Duties 保证openvpn的可行
func (duties *DutiesVPN) Duties() {
duties.Reset()
for {
time.Sleep(time.Second * 2)
if duties.PW.PingNet() {
if !duties.PW.PingVPN() {
now := time.Now().Unix()
// openvpn需要一段时间connect 才能知道是否连接成功. 所以所有一段保护时间确保这段时间内是进行connect.
if now >= atomic.LoadInt64(&duties.VPNProtectTime) {
duties.RestartConnect()
continue
}
}
}
}
}

97
main.go Normal file
View File

@ -0,0 +1,97 @@
package main
import (
"log"
"net"
"net/http"
"os"
"strconv"
"time"
)
// ErrorPanic 错误检测
func ErrorPanic(err error) {
if err != nil {
log.Panic(err)
}
}
// ErrorLog 错误检测
func ErrorLog(err error) bool {
if err != nil {
// log.Println(err)
return true
}
return false
}
// Worker 维护所有系统正常的核心类
type Worker struct {
LogFile *os.File
DNET *DutiesNet
DVPN *DutiesVPN
}
func checkTunExist() bool {
ifaces, err := net.Interfaces()
if err != nil {
log.Println(err)
return false
}
for _, i := range ifaces {
if i.Name == "tun0" {
return true
}
}
return false
}
// CmdRestartHandler 接收到该命令就重启
func (worker *Worker) CmdRestartHandler(w http.ResponseWriter, r *http.Request) {
_tm := r.PostFormValue("tm")
if _tm != "" {
tm, err := strconv.ParseInt(_tm, 10, 64)
if !ErrorLog(err) {
log.Println(tm)
worker.DNET.SetRestart()
}
}
w.Write([]byte("ok"))
}
// CmdImOKHandler 可以ping通
func (worker *Worker) CmdImOKHandler(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("ok"))
}
func testSync(f *os.File) {
for {
time.Sleep(time.Second * 1)
f.Sync()
}
}
func main() {
log.SetFlags(log.Lshortfile | log.LstdFlags)
f, err := os.OpenFile("/root/pppoe_control.log", os.O_SYNC|os.O_APPEND|os.O_CREATE|os.O_RDWR, 0660)
ErrorPanic(err)
log.SetOutput(f)
defer f.Close()
go testSync(f)
pw := &PingWorker{}
dnet := &DutiesNet{}
dnet.Default(pw)
dvpn := &DutiesVPN{}
dvpn.Default(pw)
worker := Worker{f, dnet, dvpn}
http.HandleFunc("/pppoe/restart", worker.CmdRestartHandler)
http.HandleFunc("/pppoe/imok", worker.CmdImOKHandler)
http.ListenAndServe(":8800", nil)
}

64
pingworker.go Normal file
View File

@ -0,0 +1,64 @@
package main
import (
"log"
"net/http"
"sync/atomic"
"time"
)
// PingWorker 专为ping服务, 保证不存在多余的Ping的, 让终端服务的请求合理减少.
type PingWorker struct {
LastPingVPNTime int64
LastPingVPN int64 //上次Ping的结果 0 或者 1
LastPingNetTime int64
LastPingNet int64 //上次Ping的结果 0 或者 1
}
// PingNet 确认adsl网络通信
func (pw *PingWorker) PingNet() bool {
now := time.Now().Unix()
if now-atomic.LoadInt64(&pw.LastPingNetTime) <= 2 {
return atomic.LoadInt64(&pw.LastPingNet) == 1
}
timeout := time.Duration(5 * time.Second)
client := http.Client{
Timeout: timeout,
}
_, err := client.Get("http://14.17.96.148:3333/ippool/switch/imactive")
if err != nil {
log.Println("PingNet err http://14.17.96.148:3333/ippool/switch/imactive check Network")
atomic.StoreInt64(&pw.LastPingNet, 0)
atomic.StoreInt64(&pw.LastPingNetTime, time.Now().Unix())
return false
}
atomic.StoreInt64(&pw.LastPingNet, 1)
atomic.StoreInt64(&pw.LastPingNetTime, time.Now().Unix())
return true
}
// PingVPN 确认确认外网网络通信
func (pw *PingWorker) PingVPN() bool {
now := time.Now().Unix()
if now-atomic.LoadInt64(&pw.LastPingVPNTime) <= 2 {
return atomic.LoadInt64(&pw.LastPingVPN) == 1
}
timeout := time.Duration(5 * time.Second)
client := http.Client{
Timeout: timeout,
}
_, err := client.Get("http://10.10.10.1:3333/ippool/switch/imactive")
if err != nil {
log.Println("PingVPN err http://10.10.10.1:3333/ippool/switch/imactive check Network")
atomic.StoreInt64(&pw.LastPingVPN, 0)
atomic.StoreInt64(&pw.LastPingVPNTime, time.Now().Unix())
return false
}
atomic.StoreInt64(&pw.LastPingVPN, 1)
atomic.StoreInt64(&pw.LastPingVPNTime, time.Now().Unix())
return true
}

13
pppoe_control.service Normal file
View File

@ -0,0 +1,13 @@
[Unit]
Description=pppoe_control
After=network.target
Wants=network.target
[Service]
Type=simple
PIDFile=/var/run/pppoe_control.pid
ExecStart=/usr/local/bin/pppoe_control
Restart=always
[Install]
WantedBy=multi-user.target