1
2
3
4
5
6
7
8
9
10
11
12
13
14 package main
15
16 import (
17 "bytes"
18 "encoding/json"
19 "flag"
20 "fmt"
21 "io"
22 "io/ioutil"
23 "net"
24 "net/http"
25 "os"
26 "path/filepath"
27 "time"
28 )
29
30 func main() {
31 port := flag.Int("port", 8080, "listen port")
32 dataDir := flag.String("data-dir", "/var/run/data", "data dir is the dir to write temp file, only used in io test")
33
34 flag.Parse()
35
36 s := newServer(*dataDir)
37 err := s.setupUDPServer()
38 if err != nil {
39 fmt.Println("failed to serve udp server", err)
40 os.Exit(1)
41 }
42
43 addr := fmt.Sprintf("0.0.0.0:%d", *port)
44 if err := http.ListenAndServe(addr, s.mux); err != nil {
45 fmt.Println("failed to serve http server", err)
46 os.Exit(1)
47 }
48 }
49
50 type server struct {
51 mux *http.ServeMux
52 dataDir string
53
54
55 recvBuf []byte
56 }
57
58 func newServer(dataDir string) *server {
59 s := &server{
60 mux: http.NewServeMux(),
61 dataDir: dataDir,
62 recvBuf: make([]byte, 5),
63 }
64 s.mux.HandleFunc("/ping", pong)
65 s.mux.HandleFunc("/time", s.timer)
66 s.mux.HandleFunc("/io", s.ioTest)
67 s.mux.HandleFunc("/mistake", s.mistakeTest)
68 s.mux.HandleFunc("/network/send", s.networkSendTest)
69 s.mux.HandleFunc("/network/recv", s.networkRecvTest)
70 s.mux.HandleFunc("/network/ping", s.networkPingTest)
71 s.mux.HandleFunc("/dns", s.dnsTest)
72 return s
73 }
74
75 func pong(w http.ResponseWriter, _ *http.Request) {
76 w.Write([]byte("pong"))
77 }
78
79 func (s *server) setupUDPServer() error {
80 pc, err := net.ListenPacket("udp", "0.0.0.0:1070")
81 if err != nil {
82 return err
83 }
84
85 go func() {
86 for {
87 _, _, err := pc.ReadFrom(s.recvBuf)
88 if err != nil {
89 return
90 }
91 }
92 }()
93
94 return nil
95 }
96
97
98 func (s *server) timer(w http.ResponseWriter, _ *http.Request) {
99 w.Write([]byte(time.Now().Format(time.RFC3339Nano)))
100 }
101
102
103 func (s *server) mistakeTest(w http.ResponseWriter, _ *http.Request) {
104 path := filepath.Join(s.dataDir, "e2e-test")
105 origData := []byte("hello world!!!!!!!!!!!!")
106
107 err := ioutil.WriteFile(path, origData, 0644)
108 if err != nil {
109 w.Write([]byte(fmt.Sprintf("failed to write file %v", err)))
110 return
111 }
112 gotData, err := ioutil.ReadFile(path)
113 if err != nil {
114 w.Write([]byte(err.Error()))
115 return
116 }
117 result := bytes.Equal(origData, gotData)
118 if result {
119 w.Write([]byte("false"))
120 return
121 }
122 for i := 0; i < 10; i++ {
123 tmp, err := ioutil.ReadFile(path)
124 if err != nil {
125 w.Write([]byte(err.Error()))
126 }
127 if !bytes.Equal(tmp, gotData) {
128 w.Write([]byte("true"))
129 return
130 }
131 }
132 w.Write([]byte("err"))
133 }
134
135
136 func (s *server) ioTest(w http.ResponseWriter, _ *http.Request) {
137 t1 := time.Now()
138 f, err := ioutil.TempFile(s.dataDir, "e2e-test")
139 if err != nil {
140 w.Write([]byte(fmt.Sprintf("failed to create temp file %v", err)))
141 return
142 }
143 if _, err := f.Write([]byte("hello world")); err != nil {
144 w.Write([]byte(fmt.Sprintf("failed to write file %v", err)))
145 return
146 }
147 t2 := time.Now()
148 w.Write([]byte(t2.Sub(t1).String()))
149 }
150
151
152 func (s *server) dnsTest(w http.ResponseWriter, r *http.Request) {
153
154 url, ok := r.URL.Query()["url"]
155
156 if !ok || len(url[0]) < 1 {
157 http.Error(w, "failed", http.StatusBadRequest)
158 return
159 }
160
161 ips, err := net.LookupIP(url[0])
162 if err != nil {
163 http.Error(w, "failed", http.StatusBadRequest)
164 return
165 }
166
167 if len(ips) == 0 {
168 http.Error(w, "failed", http.StatusBadRequest)
169 return
170 }
171
172 w.Write([]byte(ips[0].String()))
173 }
174
175 type networkSendTestBody struct {
176 TargetIP string `json:"targetIP"`
177 }
178
179
180 func (s *server) networkPingTest(w http.ResponseWriter, r *http.Request) {
181 var body networkSendTestBody
182
183 err := json.NewDecoder(r.Body).Decode(&body)
184 if err != nil {
185 http.Error(w, err.Error(), http.StatusBadRequest)
186 return
187 }
188
189 c := http.Client{
190 Timeout: 2 * time.Second,
191 }
192 startTime := time.Now()
193 resp, err := c.Get(fmt.Sprintf("http://%s:8080/ping", body.TargetIP))
194 if err != nil {
195 http.Error(w, err.Error(), http.StatusBadRequest)
196 return
197 }
198 defer resp.Body.Close()
199
200 endTime := time.Now()
201 out, err := ioutil.ReadAll(resp.Body)
202 if err != nil {
203 http.Error(w, err.Error(), http.StatusBadRequest)
204 return
205 }
206
207 if string(out) != "pong" {
208 http.Error(w, "response is not pong", http.StatusBadRequest)
209 return
210 }
211
212 w.Write([]byte(fmt.Sprintf("OK %d", endTime.UnixNano()-startTime.UnixNano())))
213 }
214
215
216 func (s *server) networkSendTest(w http.ResponseWriter, r *http.Request) {
217 var body networkSendTestBody
218
219 err := json.NewDecoder(r.Body).Decode(&body)
220 if err != nil {
221 http.Error(w, err.Error(), http.StatusBadRequest)
222 return
223 }
224
225 conn, err := net.DialUDP("udp", nil, &net.UDPAddr{
226 IP: net.ParseIP(body.TargetIP),
227 Port: 1070,
228 })
229 if err != nil {
230 http.Error(w, err.Error(), http.StatusBadRequest)
231 return
232 }
233 defer conn.Close()
234
235 n, err := io.WriteString(conn, "ping\n")
236 if err != nil {
237 http.Error(w, err.Error(), http.StatusBadRequest)
238 return
239 }
240 if n != 5 {
241 http.Error(w, "udp send less than 5 bytes", http.StatusBadRequest)
242 return
243 }
244 w.Write([]byte("send successfully\n"))
245 }
246
247
248 func (s *server) networkRecvTest(w http.ResponseWriter, r *http.Request) {
249 w.Write(s.recvBuf)
250
251 for index := range s.recvBuf {
252 s.recvBuf[index] = 0
253 }
254 }
255