udpconn.go 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370
  1. package service
  2. import (
  3. "context"
  4. "crypto/md5"
  5. "encoding/hex"
  6. "encoding/json"
  7. "fmt"
  8. "io"
  9. "io/ioutil"
  10. "net"
  11. "os"
  12. path2 "path"
  13. "strconv"
  14. "time"
  15. "github.com/IceWhaleTech/CasaOS/model"
  16. "github.com/IceWhaleTech/CasaOS/pkg/config"
  17. "github.com/IceWhaleTech/CasaOS/pkg/quic_helper"
  18. "github.com/IceWhaleTech/CasaOS/pkg/utils/file"
  19. model2 "github.com/IceWhaleTech/CasaOS/service/model"
  20. "github.com/IceWhaleTech/CasaOS/types"
  21. "github.com/lucas-clemente/quic-go"
  22. uuid "github.com/satori/go.uuid"
  23. )
  24. var UDPConn *net.UDPConn
  25. var PeopleMap map[string]quic.Stream
  26. var Message chan model.MessageModel
  27. var UDPAddressMap map[string]string
  28. func Dial(msg model.MessageModel, server bool) (m model.MessageModel, err error) {
  29. ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
  30. defer cancel()
  31. Message = make(chan model.MessageModel)
  32. _, port, err := net.SplitHostPort(UDPConn.LocalAddr().String())
  33. if config.ServerInfo.UDPPort != port {
  34. config.ServerInfo.UDPPort = port
  35. config.Cfg.Section("server").Key("UDPPort").SetValue(port)
  36. config.Cfg.SaveTo(config.SystemConfigInfo.ConfigPath)
  37. }
  38. p, err := strconv.Atoi(port)
  39. srcAddr := &net.UDPAddr{
  40. IP: net.IPv4zero, Port: p} //注意端口必须固定
  41. addr := UDPAddressMap[msg.To]
  42. ticket := msg.To
  43. if server {
  44. addr = config.ServerInfo.Handshake + ":9527"
  45. ticket = "bench"
  46. }
  47. dstAddr, err := net.ResolveUDPAddr("udp", addr)
  48. //DialTCP在网络协议net上连接本地地址laddr和远端地址raddr。net必须是"udp"、"udp4"、"udp6";如果laddr不是nil,将使用它作为本地地址,否则自动选择一个本地地址。
  49. //(conn)UDPConn代表一个UDP网络连接,实现了Conn和PacketConn接口
  50. session, err := quic.DialContext(ctx, UDPConn, dstAddr, srcAddr.String(), quic_helper.GetClientTlsConfig(ticket), quic_helper.GetQUICConfig())
  51. if err != nil {
  52. if msg.Type == types.PERSONDOWNLOAD {
  53. task := MyService.Download().GetDownloadById(msg.UUId)
  54. task.Error = err.Error()
  55. task.State = types.DOWNLOADERROR
  56. MyService.Download().SetDownloadError(task)
  57. }
  58. if config.SystemConfigInfo.Analyse != "False" {
  59. go MyService.Casa().PushConnectionStatus(msg.UUId, err.Error(), msg.From, msg.To, msg.Type)
  60. }
  61. return m, err
  62. }
  63. stream, err := session.OpenStreamSync(ctx)
  64. if err != nil {
  65. if msg.Type == types.PERSONDOWNLOAD {
  66. task := MyService.Download().GetDownloadById(msg.UUId)
  67. task.Error = err.Error()
  68. task.State = types.DOWNLOADERROR
  69. MyService.Download().SetDownloadError(task)
  70. }
  71. if config.SystemConfigInfo.Analyse != "False" {
  72. go MyService.Casa().PushConnectionStatus(msg.UUId, err.Error(), msg.From, msg.To, msg.Type)
  73. }
  74. session.CloseWithError(1, err.Error())
  75. return m, err
  76. }
  77. SayHello(stream, msg.To)
  78. SendData(stream, msg)
  79. go ReadContent(stream)
  80. result := <-Message
  81. stream.Close()
  82. if config.SystemConfigInfo.Analyse != "False" {
  83. go MyService.Casa().PushConnectionStatus(msg.UUId, "OK", msg.From, msg.To, msg.Type)
  84. }
  85. return result, nil
  86. }
  87. func SayHello(stream quic.Stream, to string) {
  88. msg := model.MessageModel{}
  89. msg.Type = types.PERSONHELLO
  90. msg.Data = "hello"
  91. msg.To = to
  92. msg.From = config.ServerInfo.Token
  93. msg.UUId = uuid.NewV4().String()
  94. SendData(stream, msg)
  95. }
  96. //发送数据
  97. func SendData(stream quic.Stream, m model.MessageModel) {
  98. b, _ := json.Marshal(m)
  99. prefixLength := file.PrefixLength(len(b))
  100. data := append(prefixLength, b...)
  101. stream.Write(data)
  102. }
  103. //读取数据
  104. func ReadContent(stream quic.Stream) {
  105. for {
  106. prefixByte := make([]byte, 6)
  107. _, err := io.ReadFull(stream, prefixByte)
  108. if err != nil {
  109. fmt.Println(err)
  110. time.Sleep(time.Second * 1)
  111. for k, v := range CancelList {
  112. tempPath := config.AppInfo.RootPath + "/temp" + "/" + v
  113. fmt.Println(file.RMDir(tempPath))
  114. delete(CancelList, k)
  115. }
  116. break
  117. }
  118. prefixLength, err := strconv.Atoi(string(prefixByte))
  119. if err != nil {
  120. fmt.Println(err)
  121. break
  122. }
  123. messageByte := make([]byte, prefixLength)
  124. _, err = io.ReadFull(stream, messageByte)
  125. if err != nil {
  126. fmt.Println(err)
  127. break
  128. }
  129. m := model.MessageModel{}
  130. err = json.Unmarshal(messageByte, &m)
  131. fmt.Println("客户端", m)
  132. if err != nil {
  133. fmt.Println(err)
  134. break
  135. }
  136. if m.Type == types.PERSONDOWNLOAD {
  137. dataModelByte, _ := json.Marshal(m.Data)
  138. dataModel := model.TranFileModel{}
  139. err := json.Unmarshal(dataModelByte, &dataModel)
  140. if err != nil {
  141. fmt.Println(err)
  142. continue
  143. }
  144. dataLengthByte := make([]byte, 8)
  145. _, err = io.ReadFull(stream, dataLengthByte)
  146. if err != nil {
  147. fmt.Println(err)
  148. continue
  149. }
  150. dataLength, err := strconv.Atoi(string(dataLengthByte))
  151. if err != nil {
  152. fmt.Println(err)
  153. continue
  154. }
  155. dataByte := make([]byte, dataLength)
  156. _, err = io.ReadFull(stream, dataByte)
  157. if err != nil {
  158. fmt.Println(err)
  159. continue
  160. }
  161. sum := md5.Sum(dataByte)
  162. hash := hex.EncodeToString(sum[:])
  163. if dataModel.Hash != hash {
  164. fmt.Println("hash不匹配", hash, dataModel.Hash)
  165. continue
  166. }
  167. tempPath := config.AppInfo.RootPath + "/temp" + "/" + m.UUId
  168. file.IsNotExistMkDir(tempPath)
  169. filepath := tempPath + "/" + strconv.Itoa(dataModel.Index)
  170. _, err = os.Stat(filepath)
  171. if os.IsNotExist(err) {
  172. err = ioutil.WriteFile(filepath, dataByte, 0644)
  173. task := model2.PersonDownloadDBModel{}
  174. task.UUID = m.UUId
  175. if err != nil {
  176. task.Error = err.Error()
  177. task.State = types.DOWNLOADERROR
  178. MyService.Download().SetDownloadError(task)
  179. }
  180. } else {
  181. if file.GetHashByPath(filepath) != dataModel.Hash {
  182. os.Remove(filepath)
  183. err = ioutil.WriteFile(filepath, dataByte, 0644)
  184. task := model2.PersonDownloadDBModel{}
  185. task.UUID = m.UUId
  186. if err != nil {
  187. task.Error = err.Error()
  188. task.State = types.DOWNLOADERROR
  189. MyService.Download().SetDownloadError(task)
  190. }
  191. }
  192. }
  193. files, err := ioutil.ReadDir(tempPath)
  194. if err != nil {
  195. fmt.Println(err)
  196. continue
  197. }
  198. if len(files) >= dataModel.Length {
  199. summary := MyService.Download().GetDownloadById(m.UUId)
  200. summary.State = types.DOWNLOADFINISH
  201. MyService.Download().EditDownloadState(summary)
  202. fullPath := file.GetNoDuplicateFileName(path2.Join(summary.LocalPath, summary.Name))
  203. file.SpliceFiles(tempPath, fullPath, dataModel.Length, 0)
  204. if file.GetHashByPath(fullPath) == summary.Hash {
  205. file.RMDir(tempPath)
  206. summary.State = types.DOWNLOADFINISHED
  207. MyService.Download().EditDownloadState(summary)
  208. } else {
  209. os.Remove(config.FileSettingInfo.DownloadDir + "/" + summary.Name)
  210. summary.State = types.DOWNLOADERROR
  211. summary.Error = "hash mismatch"
  212. MyService.Download().SetDownloadError(summary)
  213. }
  214. break
  215. }
  216. } else if m.Type == types.PERSONSUMMARY {
  217. dataModel := model.FileSummaryModel{}
  218. dataModelByte, _ := json.Marshal(m.Data)
  219. err := json.Unmarshal(dataModelByte, &dataModel)
  220. if err != nil {
  221. fmt.Println(err)
  222. }
  223. task := MyService.Download().GetDownloadById(m.UUId)
  224. fullPath := path2.Join(task.LocalPath, task.Name)
  225. task.State = types.DOWNLOADING
  226. if len(dataModel.Message) > 0 {
  227. task.State = types.DOWNLOADERROR
  228. task.Error = dataModel.Message
  229. }
  230. if file.Exists(fullPath) && file.GetHashByPath(fullPath) == dataModel.Hash {
  231. task.State = types.DOWNLOADFINISHED
  232. go func(from, uuid string) {
  233. m := model.MessageModel{}
  234. m.Data = ""
  235. m.From = config.ServerInfo.Token
  236. m.To = from
  237. m.Type = types.PERSONCANCEL
  238. m.UUId = uuid
  239. CancelList[uuid] = uuid
  240. Dial(m, false)
  241. }(task.From, task.UUID)
  242. }
  243. task.UUID = m.UUId
  244. task.Name = dataModel.Name
  245. task.Length = dataModel.Length
  246. task.Size = dataModel.Size
  247. task.BlockSize = dataModel.BlockSize
  248. task.Hash = dataModel.Hash
  249. task.Type = 0
  250. task.From = m.From
  251. MyService.Download().SaveDownload(task)
  252. } else if m.Type == types.PERSONCONNECTION {
  253. if len(m.Data.(string)) > 0 {
  254. UDPAddressMap[m.From] = m.Data.(string)
  255. } else {
  256. delete(UDPAddressMap, m.From)
  257. }
  258. // mi := model2.FriendModel{}
  259. // mi.Avatar = config.UserInfo.Avatar
  260. // mi.Profile = config.UserInfo.Description
  261. // mi.NickName = config.UserInfo.NickName
  262. // mi.Token = config.ServerInfo.Token
  263. msg := model.MessageModel{}
  264. msg.Type = types.PERSONHELLO
  265. msg.Data = ""
  266. msg.To = m.From
  267. msg.From = config.ServerInfo.Token
  268. msg.UUId = m.UUId
  269. go Dial(msg, false)
  270. Message <- m
  271. break
  272. } else if m.Type == "get_ip" {
  273. notify := model2.AppNotify{}
  274. notify.CustomId = m.From
  275. if len(m.Data.(string)) == 0 {
  276. if _, ok := UDPAddressMap[m.From]; ok {
  277. notify.Type = types.NOTIFY_TYPE_PERSION_FIRNED_LEAVE
  278. go MyService.Notify().SendText(notify)
  279. }
  280. delete(UDPAddressMap, m.From)
  281. Message <- m
  282. break
  283. }
  284. if _, ok := UDPAddressMap[m.From]; !ok {
  285. notify.Type = types.NOTIFY_TYPE_PERSION_FIRNED_LIVE
  286. go MyService.Notify().SendText(notify)
  287. }
  288. UDPAddressMap[m.From] = m.Data.(string)
  289. Message <- m
  290. break
  291. } else {
  292. Message <- m
  293. }
  294. }
  295. Message <- model.MessageModel{}
  296. }
  297. func SendIPToServer() {
  298. msg := model.MessageModel{}
  299. msg.Type = types.PERSONHELLO
  300. msg.Data = ""
  301. msg.From = config.ServerInfo.Token
  302. msg.To = config.ServerInfo.Token
  303. msg.UUId = uuid.NewV4().String()
  304. Dial(msg, true)
  305. }
  306. func LoopFriend() {
  307. list := MyService.Friend().GetFriendList()
  308. for i := 0; i < len(list); i++ {
  309. msg := model.MessageModel{}
  310. msg.Type = "get_ip"
  311. msg.Data = ""
  312. msg.From = config.ServerInfo.Token
  313. msg.To = list[i].Token
  314. msg.UUId = uuid.NewV4().String()
  315. Dial(msg, true)
  316. msg.Type = types.PERSONHELLO
  317. msg.Data = ""
  318. msg.From = config.ServerInfo.Token
  319. msg.To = list[i].Token
  320. msg.UUId = uuid.NewV4().String()
  321. if _, ok := UDPAddressMap[list[i].Token]; ok {
  322. go Dial(msg, false)
  323. }
  324. go func(shareId string) {
  325. user := MyService.Casa().GetUserInfoByShareId(shareId)
  326. m := model2.FriendModel{}
  327. m.Token = shareId
  328. friend := MyService.Friend().GetFriendById(m)
  329. if friend.Version != user.Version {
  330. friend.Avatar = user.Avatar
  331. friend.NickName = user.NickName
  332. friend.Profile = user.Desc
  333. friend.Version = user.Version
  334. MyService.Friend().UpdateOrCreate(friend)
  335. }
  336. }(list[i].Token)
  337. }
  338. }