usb0net.go 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  1. // Author: NiuJiuRu
  2. // Email: niujiuru@qq.com
  3. // 以下函数需"root"权限运行
  4. package ec200u
  5. import (
  6. "fmt"
  7. "io/fs"
  8. "net"
  9. "os"
  10. "os/exec"
  11. "path/filepath"
  12. "strconv"
  13. "strings"
  14. "syscall"
  15. "time"
  16. "github.com/sirupsen/logrus"
  17. "github.com/vishvananda/netlink"
  18. "hnyfkj.com.cn/rtu/linux/baseapp"
  19. )
  20. // 禁用"eth0"网口, 使其不可用
  21. func disableEth0() error {
  22. iface, err := net.InterfaceByName("eth0")
  23. if err != nil {
  24. return fmt.Errorf("未找到网口\"eth0\": %w", err)
  25. }
  26. cmd := exec.Command("ip", "link", "set", "dev", iface.Name, "down")
  27. cmd.Stdout = baseapp.Logger.WriterLevel(logrus.InfoLevel)
  28. cmd.Stderr = baseapp.Logger.WriterLevel(logrus.WarnLevel)
  29. if err := cmd.Run(); err != nil {
  30. return fmt.Errorf("关闭网口\"%s\"失败: %w", iface.Name, err)
  31. }
  32. return nil
  33. }
  34. // 启动"usb0"网口, 使其变可用
  35. func enableUSB0() error {
  36. cmd := exec.Command("ip", "link", "set", "dev", "usb0", "up")
  37. cmd.Stdout = baseapp.Logger.WriterLevel(logrus.InfoLevel)
  38. cmd.Stderr = baseapp.Logger.WriterLevel(logrus.WarnLevel)
  39. if err := cmd.Run(); err != nil {
  40. return fmt.Errorf("启动网口\"usb0\"失败: %w", err)
  41. }
  42. return nil
  43. }
  44. // 启动DHCP客户端, 请求IP地址
  45. func dialupUSB0() error {
  46. if err := enableUSB0(); err != nil {
  47. return err
  48. }
  49. usb0pid := baseapp.RUN_DIR + "/udhcpc.usb0.pid"
  50. cmd := exec.Command("udhcpc", "-b", "-i", "usb0", "-p", usb0pid)
  51. cmd.Stdout = baseapp.Logger.WriterLevel(logrus.InfoLevel)
  52. cmd.Stderr = baseapp.Logger.WriterLevel(logrus.WarnLevel)
  53. if err := cmd.Run(); err != nil {
  54. return fmt.Errorf("\"usb0\"请求地址失败: %w", err)
  55. }
  56. return nil
  57. }
  58. // 检测"usb0"网口上的"udhcpc"后台进程是否正在运行, 只保持一个实例
  59. func udhcpcUSB0Exists() (bool, error) {
  60. usb0pid := baseapp.RUN_DIR + "/udhcpc.usb0.pid"
  61. data, err := os.ReadFile(usb0pid)
  62. if err != nil {
  63. return false, err
  64. }
  65. pid, err := strconv.Atoi(strings.TrimSpace(string(data)))
  66. if err != nil {
  67. return false, err
  68. }
  69. err = syscall.Kill(pid, 0)
  70. if err == nil { // 存在
  71. return true, nil
  72. }
  73. if err == syscall.ESRCH { // 不存在
  74. return false, nil
  75. }
  76. return false, err
  77. }
  78. // 杀死"usb0"网口上的"udhcpc"进程(根据上次运行时它的PID-文件记录)
  79. func killUSB0Udhcpc() error {
  80. usb0pid := baseapp.RUN_DIR + "/udhcpc.usb0.pid"
  81. data, err := os.ReadFile(usb0pid)
  82. if err != nil {
  83. return err
  84. }
  85. pid, err := strconv.Atoi(strings.TrimSpace(string(data)))
  86. if err != nil {
  87. return err
  88. }
  89. if err := syscall.Kill(pid, syscall.SIGTERM); err != nil && err != syscall.ESRCH {
  90. syscall.Kill(pid, syscall.SIGKILL)
  91. }
  92. return nil
  93. }
  94. // 强制杀死所有运行中的"udhcpc"进程,包括驻留在后台运行的(SIGKILL)
  95. func killAllUdhcpc() {
  96. entries, err := os.ReadDir("/proc")
  97. if err != nil {
  98. return
  99. }
  100. for _, entry := range entries {
  101. name := entry.Name()
  102. pid, err := strconv.Atoi(name)
  103. if err != nil {
  104. continue
  105. }
  106. comm, err := os.ReadFile("/proc/" + name + "/comm")
  107. if err != nil {
  108. continue
  109. }
  110. if strings.TrimSpace(string(comm)) == "udhcpc" {
  111. _ = syscall.Kill(pid, syscall.SIGKILL)
  112. } // if end
  113. } /// for end
  114. }
  115. // 运行"udhcpc"后, 获取"usb0"网口分配到的IPv4地址, 并校检其合法性
  116. func getUSB0Addr() (ip, mask string, err error) {
  117. iface, err := net.InterfaceByName("usb0")
  118. if err != nil {
  119. return "", "", fmt.Errorf("找不到网络接口\"usb0\": %w", err)
  120. }
  121. addrs, err := iface.Addrs()
  122. if err != nil {
  123. return "", "", fmt.Errorf("获取\"usb0\"的地址失败: %w", err)
  124. }
  125. for _, addr := range addrs {
  126. ipNet, ok := addr.(*net.IPNet)
  127. if !ok {
  128. continue
  129. }
  130. ip4 := ipNet.IP.To4()
  131. if ip4 == nil {
  132. continue
  133. }
  134. return ip4.String(), net.IP(ipNet.Mask).String(), nil
  135. }
  136. return "", "", fmt.Errorf("在\"usb0\"上未找到有效的IPv4 地址")
  137. }
  138. // 查找并杀死所有占用"/dev/ttyUSB0"设备的进程,返回被杀死进程的PID
  139. func freeTTYUSB0() ([]int, error) {
  140. var pids []int
  141. seen := make(map[int]struct{})
  142. err := filepath.WalkDir("/proc", func(path string, d fs.DirEntry, walkErr error) error {
  143. if walkErr != nil {
  144. return nil
  145. }
  146. if filepath.Base(filepath.Dir(path)) != "fd" {
  147. return nil
  148. }
  149. link, err := os.Readlink(path)
  150. if err != nil || link != "/dev/ttyUSB0" {
  151. return nil
  152. }
  153. parts := strings.Split(path, "/")
  154. if len(parts) < 3 {
  155. return nil
  156. }
  157. pid, err := strconv.Atoi(parts[2])
  158. if err != nil {
  159. return nil
  160. }
  161. if _, exists := seen[pid]; exists {
  162. return nil // 已处理过这个PID, 跳过
  163. }
  164. seen[pid] = struct{}{}
  165. if err := syscall.Kill(pid, syscall.SIGTERM); err != nil && err != syscall.ESRCH {
  166. syscall.Kill(pid, syscall.SIGKILL)
  167. }
  168. pids = append(pids, pid)
  169. return nil
  170. })
  171. return pids, err
  172. }
  173. // 定时检测"usb0"网卡上的"udhcpc"后台服务进程, 发现退出时自动拉起
  174. func monitorUSB0Udhcpc(exitCh <-chan struct{}) {
  175. t := time.NewTicker(time.Duration(5) * time.Second)
  176. defer t.Stop()
  177. for {
  178. select {
  179. case <-t.C:
  180. bExists, _ := udhcpcUSB0Exists()
  181. if !bExists { // 清场一次
  182. killAllUdhcpc()
  183. disableEth0()
  184. }
  185. if !bExists && dialupUSB0() == nil { // 重新进场
  186. ip, mask, _ := getUSB0Addr()
  187. baseapp.Logger.Warnf("[%s] \"usb0\"重新分配的地址: %s/%s!", MODULE_NAME, ip, mask)
  188. }
  189. case <-exitCh:
  190. return
  191. } // select end
  192. } // for end
  193. }
  194. func isInterfaceUp(name string) (bool, error) {
  195. link, err := netlink.LinkByName(name)
  196. if err != nil {
  197. return false, err
  198. }
  199. return link.Attrs().Flags&net.FlagUp != 0, nil
  200. }
  201. func waitUSB0Carrier(timeoutMs int) (bool, error) {
  202. interval, elapsed := 50, 0
  203. for elapsed < timeoutMs {
  204. data, err := os.ReadFile("/sys/class/net/usb0/carrier")
  205. if err == nil && strings.TrimSpace(string(data)) == "1" {
  206. return true, nil
  207. }
  208. time.Sleep(time.Millisecond * time.Duration(interval))
  209. elapsed += interval
  210. }
  211. return false, fmt.Errorf("usb0 carrier not up after %d ms", timeoutMs)
  212. }
  213. func Is4GCableConnected() (bool, error) {
  214. if up, _ := isInterfaceUp("usb0"); !up {
  215. err := enableUSB0()
  216. if err != nil {
  217. return false, err
  218. }
  219. }
  220. return waitUSB0Carrier(2000)
  221. }