Add: internet default routes
This commit is contained in:
parent
5065cfdfca
commit
3f5412fac0
@ -1,15 +1,27 @@
|
||||
package internet
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"os/exec"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"gitea.unprism.ru/KRBL/sim-modem/api/modem/at"
|
||||
)
|
||||
|
||||
const (
|
||||
pingPacketsCount = 3
|
||||
pingTimeout = 5
|
||||
inetConnectedTimeout = 2 * time.Second
|
||||
pingAddr = "8.8.8.8"
|
||||
ifName = "ppp0" // Interface name
|
||||
inetMetric = 2000
|
||||
)
|
||||
|
||||
type conn struct {
|
||||
logger *log.Logger
|
||||
port at.Port
|
||||
@ -18,6 +30,10 @@ type conn struct {
|
||||
|
||||
isConnectExecuted bool
|
||||
isInited bool
|
||||
isRouteSet bool
|
||||
|
||||
connectTime time.Time
|
||||
gw string // Gateway
|
||||
}
|
||||
|
||||
type Conn interface {
|
||||
@ -26,6 +42,9 @@ type Conn interface {
|
||||
Connect() error
|
||||
Disconnect() error
|
||||
|
||||
SetDefaultRouteTable() error
|
||||
UnsetDefaultRouteTable() error
|
||||
|
||||
IsConnected() bool // Check interface existance
|
||||
Ping() error
|
||||
|
||||
@ -34,10 +53,12 @@ type Conn interface {
|
||||
|
||||
func New(logger *log.Logger, port at.Port) Conn {
|
||||
return &conn{
|
||||
logger: logger,
|
||||
port: port,
|
||||
logger: logger,
|
||||
port: port,
|
||||
|
||||
isConnectExecuted: false,
|
||||
isInited: false,
|
||||
isRouteSet: false,
|
||||
}
|
||||
}
|
||||
|
||||
@ -60,12 +81,6 @@ func (c *conn) Connect() error {
|
||||
return fmt.Errorf("already connected")
|
||||
}
|
||||
// Check signal
|
||||
// if ok, err := utils.CheckService(c.port, c.logger); err != nil || !ok {
|
||||
// if err != nil {
|
||||
// return fmt.Errorf("check service: %w", err)
|
||||
// }
|
||||
// return fmt.Errorf("no service")
|
||||
// }
|
||||
|
||||
resp, err := exec.Command("pon", pppConfigName).Output()
|
||||
if err != nil {
|
||||
@ -74,11 +89,15 @@ func (c *conn) Connect() error {
|
||||
if len(resp) > 0 {
|
||||
c.logger.Println("pon response:", string(resp))
|
||||
}
|
||||
|
||||
c.isConnectExecuted = true
|
||||
|
||||
// Set default route
|
||||
|
||||
c.connectTime = time.Now()
|
||||
c.gw, err = c.GetHostIp()
|
||||
if err != nil {
|
||||
return fmt.Errorf("get host ip: %w", err)
|
||||
}
|
||||
c.logger.Println("\x1b[38;2;0;255;0mInternet connected.\x1b[38;2;255;255;255m")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -97,30 +116,156 @@ func (c *conn) Disconnect() error {
|
||||
c.logger.Println("poff response:", string(resp))
|
||||
}
|
||||
c.isConnectExecuted = false
|
||||
c.logger.Println("\x1b[38;2;0;255;0mInternet disconnected.\x1b[38;2;255;255;255m")
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *conn) Ping() error {
|
||||
// Test - try to connect to Google DNS
|
||||
// ping -I ppp0 8.8.8.8
|
||||
resp, err := exec.Command("ping", "8.8.8.8").Output()
|
||||
func (c *conn) SetDefaultRouteTable() error {
|
||||
// route add -net default gw 10.64.64.64 metric 2000 dev ppp0
|
||||
resp, err := exec.Command("route", "add", "-net", "default", "gw", c.gw, "metric", strconv.Itoa(inetMetric), "dev", ifName).Output()
|
||||
if err != nil {
|
||||
return fmt.Errorf("execute add cmd: %w", err)
|
||||
}
|
||||
// Check response
|
||||
if len(resp) != 0 {
|
||||
c.logger.Println("Not nil response:", string(resp))
|
||||
}
|
||||
c.isRouteSet = true
|
||||
c.logger.Println("\x1b[38;2;0;255;0mInternet route table set.\x1b[38;2;255;255;255m")
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *conn) UnsetDefaultRouteTable() error {
|
||||
if !c.isRouteSet {
|
||||
return fmt.Errorf("route table is not set")
|
||||
}
|
||||
resp, err := exec.Command("route", "del", "-net", "default", "gw", c.gw, "metric", strconv.Itoa(inetMetric), "dev", ifName).Output()
|
||||
if err != nil {
|
||||
return fmt.Errorf("execute del cmd: %w", err)
|
||||
}
|
||||
// Check response
|
||||
if len(resp) != 0 {
|
||||
c.logger.Println("Not nil response:", string(resp))
|
||||
}
|
||||
c.logger.Println("\x1b[38;2;0;255;0mInternet route table unset.\x1b[38;2;255;255;255m")
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *conn) ping(flags []string, timeout int) error {
|
||||
c.logger.Println("Ping", flags[len(flags)-1])
|
||||
|
||||
// Just counter
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
go func(c *conn, ctx context.Context) {
|
||||
for i := 0; i < timeout; i++ {
|
||||
c.logger.Printf("Ping %d/%d", i, timeout)
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return
|
||||
case <-time.After(time.Second):
|
||||
}
|
||||
}
|
||||
}(c, ctx)
|
||||
|
||||
// Executing cmd
|
||||
cmd := exec.Command("ping", flags...)
|
||||
resp, err := cmd.Output()
|
||||
cancel()
|
||||
if err != nil {
|
||||
c.logger.Println("Ping default interface cmd error:", err)
|
||||
}
|
||||
c.logger.Println("Ping default interface resp:", string(resp))
|
||||
|
||||
resp, err = exec.Command("ping", "-I", "ppp0", "8.8.8.8").Output()
|
||||
if err != nil {
|
||||
c.logger.Println("Ping ppp0 interface cmd error:", err)
|
||||
// Parse
|
||||
lines := strings.Split(string(resp), "\n")
|
||||
|
||||
// Look for string "--- *.*.*.* ping statistics ---" by first simbol '-'
|
||||
stLineI := 0
|
||||
searchStLineLoop:
|
||||
for i, l := range lines {
|
||||
if len(l) > 0 && l[0] == '-' {
|
||||
stLineI = i + 1
|
||||
break searchStLineLoop
|
||||
}
|
||||
}
|
||||
c.logger.Println("Ping ppp0 interface resp:", string(resp))
|
||||
if stLineI == 0 || stLineI >= len(lines) {
|
||||
return fmt.Errorf("failed to find statistics line: %d", stLineI)
|
||||
}
|
||||
stStr := lines[stLineI]
|
||||
|
||||
if strings.Contains(string(resp), "Destination Host Unreachable") || strings.Contains(string(resp), "Destination Net Unreachable") {
|
||||
return fmt.Errorf("ping response: %s", string(resp))
|
||||
// Get third value "packet lost"
|
||||
values := strings.Split(stStr, ",")
|
||||
if len(values) < 3 {
|
||||
return fmt.Errorf("invalid statistic values(len): [%s]", values)
|
||||
}
|
||||
|
||||
// Get number
|
||||
words := strings.Split(values[2], " ")
|
||||
if len(words) < 2 {
|
||||
return fmt.Errorf("invalid \"packets lost\" value(words count): [%s]", words)
|
||||
}
|
||||
// First is ''
|
||||
// Second is '...%'
|
||||
packetsLost, err := strconv.Atoi(words[1][:len(words[1])-1]) // Without '%' char
|
||||
if err != nil {
|
||||
return fmt.Errorf("parse \"packets lost\" value: %w", err)
|
||||
}
|
||||
if packetsLost == 100 {
|
||||
return fmt.Errorf("lost all packages")
|
||||
}
|
||||
if packetsLost > 0 {
|
||||
c.logger.Printf("lost some packets: %d%%\n", packetsLost)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *conn) GetHostIp() (string, error) {
|
||||
if !c.isConnectExecuted {
|
||||
return "", fmt.Errorf("internet not connected")
|
||||
}
|
||||
// Wait some time for system to setup route table
|
||||
time.Sleep(time.Until(c.connectTime.Add(inetConnectedTimeout)))
|
||||
|
||||
// Execute cmd
|
||||
resp, err := exec.Command("route").Output()
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("exec route cmd: %w", err)
|
||||
}
|
||||
// Check and split to lines
|
||||
lines := strings.Split(string(resp), "\n")
|
||||
if len(lines) <= 3 || lines[0] != "Kernel IP routing table" {
|
||||
return "", fmt.Errorf("invalid route response: [% s]", lines)
|
||||
}
|
||||
// Search line about ppp interface
|
||||
searchLoop:
|
||||
for _, l := range lines[1:] {
|
||||
words := strings.Fields(l)
|
||||
if len(words) != 8 {
|
||||
/// c.logger.Printf("invalid route line(words number): [%s]\n", words)
|
||||
continue searchLoop
|
||||
}
|
||||
if words[7] == ifName {
|
||||
if words[3] != "UH" {
|
||||
// c.logger.Println("invalid flags")
|
||||
continue searchLoop
|
||||
}
|
||||
return words[0], nil
|
||||
}
|
||||
}
|
||||
return "", fmt.Errorf("found no suitable ppp interface")
|
||||
}
|
||||
|
||||
func (c *conn) PingDefault() error {
|
||||
return c.ping([]string{"-c", strconv.Itoa(pingPacketsCount), "-w", strconv.Itoa(pingTimeout), pingAddr}, pingTimeout)
|
||||
}
|
||||
|
||||
func (c *conn) PingPPP() error {
|
||||
return c.ping([]string{"-I", ifName, "-c", string(pingPacketsCount), "-w", string(pingTimeout), pingAddr}, pingTimeout)
|
||||
}
|
||||
|
||||
func (c *conn) Ping() error {
|
||||
return c.PingDefault()
|
||||
}
|
||||
|
||||
func (c *conn) IsConnected() bool {
|
||||
if !c.isConnectExecuted {
|
||||
return false
|
||||
@ -140,7 +285,7 @@ func (c *conn) IsConnected() bool {
|
||||
continue
|
||||
}
|
||||
interfaceName := strings.Split(l, ":")[0]
|
||||
if interfaceName == "ppp0" {
|
||||
if interfaceName == ifName {
|
||||
return true
|
||||
}
|
||||
}
|
||||
@ -149,8 +294,17 @@ func (c *conn) IsConnected() bool {
|
||||
|
||||
func (c *conn) Close() error {
|
||||
c.isInited = false
|
||||
if err := c.Disconnect(); err != nil {
|
||||
return fmt.Errorf("diconnect: %w", err)
|
||||
// Unset route table
|
||||
if c.isRouteSet {
|
||||
if err := c.UnsetDefaultRouteTable(); err != nil {
|
||||
c.logger.Println("unset route table error:", err.Error())
|
||||
}
|
||||
}
|
||||
// Disconnect
|
||||
if c.isConnectExecuted {
|
||||
if err := c.Disconnect(); err != nil {
|
||||
c.logger.Println("diconnect error:", err.Error())
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -130,12 +130,12 @@ func (m *modem) Init() error {
|
||||
// submodulesLogger := io.Discard // FOR less logs
|
||||
|
||||
m.logger.Println("=============================== Init submodules")
|
||||
// m.ic = internet.New(log.New(submodulesLogger, "modem-internet : ", log.LstdFlags), m.port)
|
||||
// if err := m.ic.Init(ports[1]); err != nil {
|
||||
// m.logger.Printf("\x1b[38;2;255;0;0mInternet: %s\x1b[38;2;255;255;255m\n", err.Error())
|
||||
// } else {
|
||||
// m.logger.Println("\x1b[38;2;0;255;0mInternet OK\x1b[38;2;255;255;255m")
|
||||
// }
|
||||
m.ic = internet.New(log.New(submodulesLogger, "modem-internet : ", log.LstdFlags), m.port)
|
||||
if err := m.ic.Init(ports[1]); err != nil {
|
||||
m.logger.Printf("\x1b[38;2;255;0;0mInternet: %s\x1b[38;2;255;255;255m\n", err.Error())
|
||||
} else {
|
||||
m.logger.Println("\x1b[38;2;0;255;0mInternet OK\x1b[38;2;255;255;255m")
|
||||
}
|
||||
|
||||
// m.sms = sms.New(log.New(submodulesLogger, "modem-sms : ", log.LstdFlags), m.port)
|
||||
// if err := m.sms.Init(); err != nil {
|
||||
@ -203,6 +203,7 @@ func (m *modem) GetTime() (time.Time, error) {
|
||||
return time.Time{}, fmt.Errorf("invalid values (len): [%s]", values)
|
||||
}
|
||||
timeStr := values[1]
|
||||
m.logger.Println("Raw time:", timeStr)
|
||||
if len(timeStr) != len("yy/MM/dd,hh:mm:ss+zz") {
|
||||
return time.Time{}, fmt.Errorf("invalid time string: %s", timeStr)
|
||||
}
|
||||
@ -361,6 +362,7 @@ func (m *modem) setupPort() error {
|
||||
m.printCmd("ATE0") // Sometimes enables echo mode
|
||||
m.printCmd("AT+CGPSFTM=0") // Sometimes does not turn off nmea
|
||||
m.printCmd("AT+CMEE=2") // Turn on errors describtion
|
||||
m.printCmd("AT+CTZU=1") // Turn on time update
|
||||
|
||||
return nil
|
||||
}
|
||||
|
59
main.go
59
main.go
@ -2,6 +2,7 @@ package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"os/signal"
|
||||
@ -28,15 +29,45 @@ func main() {
|
||||
log.Println("END")
|
||||
}
|
||||
|
||||
var m modem.Modem
|
||||
var logger *log.Logger
|
||||
|
||||
func InetInit() error {
|
||||
// Connect to internet
|
||||
if err := m.Ic().Connect(); err != nil {
|
||||
return fmt.Errorf("connect to internet: %w", err)
|
||||
}
|
||||
|
||||
// Setup route table
|
||||
// Linux now always manage to add ppp0 interface to route table in time so it is better to add ф loop here
|
||||
setupRouteTableLoop:
|
||||
for {
|
||||
if err := m.Ic().SetDefaultRouteTable(); err != nil {
|
||||
logger.Println("set route table:", err.Error())
|
||||
time.Sleep(2 * time.Second)
|
||||
} else {
|
||||
break setupRouteTableLoop
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func Cmd(cmd string) {
|
||||
resp, err := m.At().SendWithTimeout(cmd, 50*time.Millisecond)
|
||||
logger.Println(cmd, "===>", resp, err)
|
||||
}
|
||||
|
||||
func mainE(ctx context.Context) error {
|
||||
logger := log.New(os.Stdout, "main : ", log.LstdFlags)
|
||||
m := modem.New(log.New(logger.Writer(), "modem : ", log.LstdFlags))
|
||||
logger = log.New(os.Stdout, "main : ", log.LstdFlags)
|
||||
m = modem.New(log.New(logger.Writer(), "modem : ", log.LstdFlags))
|
||||
|
||||
logger.Println("||||||||||||||||| INIT |||||||||||||||")
|
||||
|
||||
// If power is down modem won't find suitable devices add will try to send powerOn signal and then try again
|
||||
initLoop:
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
case <-ctx.Done(): // For interupt
|
||||
logger.Println("Break init loop")
|
||||
return nil
|
||||
default:
|
||||
@ -51,26 +82,23 @@ initLoop:
|
||||
break initLoop
|
||||
}
|
||||
}
|
||||
|
||||
// Final check for sure
|
||||
if !m.IsConnected() {
|
||||
logger.Println("Modem is not connected")
|
||||
return nil
|
||||
}
|
||||
// Close() deinits everything recursively
|
||||
defer func() {
|
||||
logger.Println("||||||||||||||||| CLOSE |||||||||||||||")
|
||||
m.Close()
|
||||
}()
|
||||
|
||||
// Connect to internet
|
||||
// if err := m.Ic().Connect(); err != nil {
|
||||
// return fmt.Errorf("connect to internet: %w", err)
|
||||
// }
|
||||
if err := InetInit(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
logger.Println("||||||||||||||||| SMS |||||||||||||||||")
|
||||
Cmd := func(cmd string) {
|
||||
resp, err := m.At().SendWithTimeout(cmd, 50*time.Millisecond)
|
||||
logger.Println(cmd, "===>", resp, err)
|
||||
}
|
||||
_ = Cmd
|
||||
|
||||
// Select ME PMS
|
||||
// logger.Println("SEND SMS")
|
||||
@ -92,15 +120,18 @@ initLoop:
|
||||
logger.Println("Break main loop")
|
||||
return nil
|
||||
default:
|
||||
// Cmd("AT+CPSI?")
|
||||
Cmd("AT+CPSI?")
|
||||
// Cmd("AT+CSQ")
|
||||
// Cmd("AT+CTZU?")
|
||||
// Cmd("AT+CPIN?")
|
||||
// Cmd("AT+CCLK?")
|
||||
// logger.Println(m.Gps().GetStatus())
|
||||
// m.Update()
|
||||
// st, _ := m.Gps().GetStatus()
|
||||
// logger.Printf("GPS STATUS: %+v", st)
|
||||
// logger.Printf("GPS DATA: %+v", m.GetData())
|
||||
logger.Println(m.GetTime())
|
||||
// logger.Println(m.GetTime())
|
||||
logger.Println(m.Ic().Ping())
|
||||
time.Sleep(2 * time.Second)
|
||||
}
|
||||
// Cmd("AT+CSQ")
|
||||
|
Loading…
Reference in New Issue
Block a user