main.go 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. // SPDX-FileCopyrightText: 2023 The Pion community <https://pion.ly>
  2. // SPDX-License-Identifier: MIT
  3. // Package main implements a simple example demonstrating a Pion-to-Pion ICE connection
  4. package main
  5. import (
  6. "bufio"
  7. "context"
  8. "flag"
  9. "fmt"
  10. "net/http"
  11. "net/url"
  12. "os"
  13. "time"
  14. "github.com/pion/ice/v2"
  15. "github.com/pion/randutil"
  16. )
  17. //nolint:gochecknoglobals
  18. var (
  19. isControlling bool
  20. iceAgent *ice.Agent
  21. remoteAuthChannel chan string
  22. localHTTPPort, remoteHTTPPort int
  23. )
  24. // HTTP Listener to get ICE Credentials from remote Peer
  25. func remoteAuth(_ http.ResponseWriter, r *http.Request) {
  26. if err := r.ParseForm(); err != nil {
  27. panic(err)
  28. }
  29. remoteAuthChannel <- r.PostForm["ufrag"][0]
  30. remoteAuthChannel <- r.PostForm["pwd"][0]
  31. }
  32. // HTTP Listener to get ICE Candidate from remote Peer
  33. func remoteCandidate(_ http.ResponseWriter, r *http.Request) {
  34. if err := r.ParseForm(); err != nil {
  35. panic(err)
  36. }
  37. c, err := ice.UnmarshalCandidate(r.PostForm["candidate"][0])
  38. if err != nil {
  39. panic(err)
  40. }
  41. if err := iceAgent.AddRemoteCandidate(c); err != nil { //nolint:contextcheck
  42. panic(err)
  43. }
  44. }
  45. func main() { //nolint
  46. var (
  47. err error
  48. conn *ice.Conn
  49. )
  50. remoteAuthChannel = make(chan string, 3)
  51. flag.BoolVar(&isControlling, "controlling", false, "is ICE Agent controlling")
  52. flag.Parse()
  53. if isControlling {
  54. localHTTPPort = 9000
  55. remoteHTTPPort = 9001
  56. } else {
  57. localHTTPPort = 9001
  58. remoteHTTPPort = 9000
  59. }
  60. http.HandleFunc("/remoteAuth", remoteAuth)
  61. http.HandleFunc("/remoteCandidate", remoteCandidate)
  62. go func() {
  63. if err = http.ListenAndServe(fmt.Sprintf(":%d", localHTTPPort), nil); err != nil { //nolint:gosec
  64. panic(err)
  65. }
  66. }()
  67. if isControlling {
  68. fmt.Println("Local Agent is controlling")
  69. } else {
  70. fmt.Println("Local Agent is controlled")
  71. }
  72. fmt.Print("Press 'Enter' when both processes have started")
  73. if _, err = bufio.NewReader(os.Stdin).ReadBytes('\n'); err != nil {
  74. panic(err)
  75. }
  76. iceAgent, err = ice.NewAgent(&ice.AgentConfig{
  77. NetworkTypes: []ice.NetworkType{ice.NetworkTypeUDP4},
  78. })
  79. if err != nil {
  80. panic(err)
  81. }
  82. // When we have gathered a new ICE Candidate send it to the remote peer
  83. if err = iceAgent.OnCandidate(func(c ice.Candidate) {
  84. if c == nil {
  85. return
  86. }
  87. _, err = http.PostForm(fmt.Sprintf("http://localhost:%d/remoteCandidate", remoteHTTPPort), //nolint
  88. url.Values{
  89. "candidate": {c.Marshal()},
  90. })
  91. if err != nil {
  92. panic(err)
  93. }
  94. }); err != nil {
  95. panic(err)
  96. }
  97. // When ICE Connection state has change print to stdout
  98. if err = iceAgent.OnConnectionStateChange(func(c ice.ConnectionState) {
  99. fmt.Printf("ICE Connection State has changed: %s\n", c.String())
  100. }); err != nil {
  101. panic(err)
  102. }
  103. // Get the local auth details and send to remote peer
  104. localUfrag, localPwd, err := iceAgent.GetLocalUserCredentials()
  105. if err != nil {
  106. panic(err)
  107. }
  108. _, err = http.PostForm(fmt.Sprintf("http://localhost:%d/remoteAuth", remoteHTTPPort), //nolint
  109. url.Values{
  110. "ufrag": {localUfrag},
  111. "pwd": {localPwd},
  112. })
  113. if err != nil {
  114. panic(err)
  115. }
  116. remoteUfrag := <-remoteAuthChannel
  117. remotePwd := <-remoteAuthChannel
  118. if err = iceAgent.GatherCandidates(); err != nil {
  119. panic(err)
  120. }
  121. // Start the ICE Agent. One side must be controlled, and the other must be controlling
  122. if isControlling {
  123. conn, err = iceAgent.Dial(context.TODO(), remoteUfrag, remotePwd)
  124. } else {
  125. conn, err = iceAgent.Accept(context.TODO(), remoteUfrag, remotePwd)
  126. }
  127. if err != nil {
  128. panic(err)
  129. }
  130. // Send messages in a loop to the remote peer
  131. go func() {
  132. for {
  133. time.Sleep(time.Second * 3)
  134. val, err := randutil.GenerateCryptoRandomString(15, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
  135. if err != nil {
  136. panic(err)
  137. }
  138. if _, err = conn.Write([]byte(val)); err != nil {
  139. panic(err)
  140. }
  141. fmt.Printf("Sent: '%s'\n", val)
  142. }
  143. }()
  144. // Receive messages in a loop from the remote peer
  145. buf := make([]byte, 1500)
  146. for {
  147. n, err := conn.Read(buf)
  148. if err != nil {
  149. panic(err)
  150. }
  151. fmt.Printf("Received: '%s'\n", string(buf[:n]))
  152. }
  153. }